掲示板の実装(1)-ページルーティングとAPI設計

13968 ワード

NodeJSサーバの設定

  • npm initを使用してpackage.jsonファイルを作成

  • scriptの開始部分をnodemon serverに置き換えます
    :これは、nodemonというモジュールを使用してサーバを起動することを意味します.
  • npm i nodemon
  • npm i express
  • 次の例では、npm run devでバックグラウンドコマンドを実行するので、startセクションを変更する必要はありません.
    "scripts": {
        " start": "node server/index.js",
        "backend": "nodemon server/index.js",
        "frontend": "npm run start --prefix client",
        "dev": "concurrently \"npm run backend\" \"npm run start --prefix client\""
      },
    server/index.js
    const express = require("express");
    const app = express();
    const path = require("path");
    const cors = require('cors')
    const session = require("express-sesstion")
    const bodyParser = require("body-parser");
    const cookieParser = require("cookie-parser");
    
    const config = require("./config/key");
    
    // const mongoose = require("mongoose");
    // mongoose
    //   .connect(config.mongoURI, { useNewUrlParser: true })
    //   .then(() => console.log("DB connected"))
    //   .catch(err => console.error(err));
    
    const mongoose = require("mongoose");
    const connect = mongoose.connect(config.mongoURI,
      {
        useNewUrlParser: true, useUnifiedTopology: true,
        useCreateIndex: true, useFindAndModify: false
      })
      .then(() => console.log('MongoDB Connected...'))
      .catch(err => console.log(err));
    
    app.use(cors())
    
    //to not get any deprecation warning or error
    //support parsing of application/x-www-form-urlencoded post data
    app.use(bodyParser.urlencoded({ extended: true })); //extended: true :  배열같은 추가적인 데이터를 쓸수있도록
    //to get json data
    // support parsing of application/json type post data
    app.use(bodyParser.json()); //데이터를 주고받을때 json 형식 사용
    app.use(cookieParser());
    
    app.use(session({
      resave: false,
      saveUninitialized : true,
      secret: "flowersayo",
      cookie:{
        httpOnly: true, //https 
        secure: false
      }
    })
    );
    app.use('/api/users', require('./routes/users')); // router로 분리 
    
    
    //use this to show the image you have in node js server to client (react js)
    //https://stackoverflow.com/questions/48914987/send-image-path-from-node-js-express-server-to-react-client
    app.use('/uploads', express.static('uploads'));
    
    // Serve static assets if in production
    if (process.env.NODE_ENV === "production") {
    
      // Set static folder   
      // All the javascript and css files will be read and served from this folder
      app.use(express.static("client/build"));
    
      // index.html for all page routes    html or routing and naviagtion
      app.get("*", (req, res) => {
        res.sendFile(path.resolve(__dirname, "../client", "build", "index.html"));
      });
    }
    
    const port = process.env.PORT || 5000
    
    app.listen(port, () => { //서버를 실제적으로 실행하는 부분
      console.log(`Server Listening on ${port}`)
    });

    ネストされたルーティングが必要


    苦悩の始まり?
    ゲームページを実現するために必要なすべてのページをルーティングすると同時に、突然アプリケーションが作成されます.jsのすべてのページを
    ルーティングが有効かどうか考えています.例えば、/forum/freeページに入ると、フリー掲示板の完全なリストが表示され、/forum/free/{글아이디}に特定の記事の詳細ページが表示されている場合、どうすればいいですか?/forum/freeでswitch処理をする方法はないかと考えています.もし存在するページが1億個あったら?1つの素子に1億個の素子をすべてルーティングすることは不可能だと思います.検索してみると중첩 라우팅まで学べます.

    https://www.daleseo.com/react-router-nested/
    :アプリケーションに必要なすべてのパスとコンポーネント間のマッピングが、上記の最上位コンポーネント上で行われる場合、アプリケーションの規模が大きくなるにつれてメンテナンスが困難になります.しかし、サブコンポーネントレベルごとにより低レベルのルーティングをモジュール化できると、メンテナンスが容易になり、全体的により柔軟なルーティング実装を実現することができる.
    これからは、<App>コンポーネントを介して/forum/freeパスをフリーフォーラムページ全体に接続し、<FreeforumPage>コンポーネントを使用して最初のルーティングを行い、<FreeforumPage>で2番目のルーティングを行います.また,同様の作業も攻略掲示板,創意掲示板で繰り返し行われる.
    1回目のルーティングを実施する-App.jsに次のコードを追加
    <Route exact path="/forum" component={Auth(ForumPage, true)} />
     <Route exact path="/forum/free" component={Auth(FreeForumPage, true)} />
              <Route exact path="/forum/playtip" component={Auth(PlayTipForumPage, true)} />
              <Route exact path="/forum/idea" component={Auth(IdeaForumPage, true)} />
    ネストされたルーティングを実装するには、まず、ReactRouterの<Route>コンポーネントのcomponent propにどの値が渡されるかを知る必要がある.React Routerは、matchlocationhistoryの3つの支柱を渡します.さらに,オーバーラップルーティングを実現する際に,特にマッチング情報を含むmatchを用いて試みる.match.urlは、<Link>コンポーネントに使用され、マッチングされる.pathは<Route>素子に用いられる.match.urlとmatch.pathの違いはmatchです.urlは実際には一致するURL文字列(ex./articles/1)を含み、matchは.pathには、一致するパスのモード(ex./article/:id)が含まれます.
    ❤ console.ログの結果

    2回目のルーティングの実装
    import React from 'react'
    import { Route, Switch } from "react-router-dom";
    import PostViewPage from './section/PostViewPage';
    import PostCreatePage from './section/PostCreatePage';
    
    function FreeForumPage({match}) {
    //match.path가 free/
        return (
            <div>
              <Route exact path={`${match.path}/create`} component={PostCreatePage} /> 
              <Route exact path={`${match.path}/:postId`} component={PostViewPage} />
            </div>
        )
    }
    
    export default FreeForumPage
    ? exactの存在とexactの存在の違い
    ホームコンポーネントをルーティングするときにexcelが設定されている場合、ホームコンポーネントはパスが完全に一致している場合にのみオフセットされます.逆にexceptが設定されていない場合は、/problem/exなどのサブリンクがあっても、問題のある構成部品はオフセットできます.

    プリプロセッシング


    ページルーティングが完了し、CRUDの実装が開始されます.
  • App.「ckeditor 4-react」からjsのCKeditorをインポートします.その他
  • npm i ckeditor4-react
  • import CKEditor from 'ckeditor4-react';
  • ブートモジュールのインストール
    https://flamingotiger.github.io/style/react-bootstrap/
  • npm install react-bootstrap bootstrap
  • 最上位ルートファイルsrc/index.jsまたはApp.jsファイルに次のスタイルを追加します.import 'bootstrap/dist/css/bootstrap.min.css';
  • インストール
  • jQuery
    https://itprogramming119.tistory.com/entry/React-React%EC%97%90%EC%84%9C-jQuery-%EC%82%AC%EC%9A%A9-%EB%B0%A9%EB%B2%95
  • npm install jquery
  • import $ from 'jquery';
  • プリプロセッシング
    import React from 'react'
    import {CKEditor} from 'ckeditor4-react';
    import {Button,Form} from 'react-bootstrap';
    import axios from 'axios';
    import $ from 'jquery';
    import {} from 'jquery.cookie';
    
    axios.defaults.withCredentials=true;
    const headers = {withCredentials: true};
    
    function PostCreatePage({match}) {
      console.log(match)
      return (
          <div style={{color:'white'}}>
             <CKEditor></CKEditor>
             
          </div>
      )
    }
    
    export default PostCreatePage

    API設計

  • 要求生成文書:/api/board/create
  • // 게시글 추가하기
    router.post('/create',(req,res)=>{
        const board = new Board(req.body)
    
        board.save((err,doc)=>{
            if(err) return res.status(400).send(err);
            else res.status(200).json({success: true,doc:doc})
        });
    })
  • 要求削除記事:/api/board/delete
  • 
    // 게시글 삭제
    router.post('/remove',(request,response)=>{ 
        Board.findOneAndDelete({postId: request.body.postId ,writer : request.body.writer}) // 이 두 조건에 해당하는 db모델 지우기. 
        .exec((err,doc)=>{
             if(err) return response.status(400).send(err);
             else response.status(200).json({success: true, doc :doc}); 
        })
     })
  • 文書の修正を要求:/api/board/update
  • 
    //게시글 수정 요청
    router.post('/update',(req,res)=>{
        Board.update(
            {postId: req.body.postId},
            {$set:{
                writer: req.body.writer,
                title : req.body.title,
                content : req.body.content
            }})
            .exec((err,doc)=>{
                if(err) return response.status(400).send(err);
                else response.status(200).json({success: true, doc :doc}); 
            });
        
    });
    
  • 特定の投稿の読み込みを要求:/api/board/getBoardDetail
  • 
    // 특정 게시글 내용 불러오기 요청
    router.post('/getBoardDetail',(req,res)=>{
       
        Favorite.find({postId: req.body.postId})
        .exec((err,board)=>{ 
            if(err) return response.status(400).send(arr)
            return response.status(200).json({success: true, board})
        })
        
    
    });
    
    
  • リクエストフル投稿:/api/board/getBoardList
  • 
    // 전체 게시글 내용 불러오기 요청
    router.post('/getBoardList',(req,res)=>{
       
        Favorite.find({sort:{createdAt:-1}})
        .exec((err,boards)=>{ 
            if(err) return response.status(400).send(arr)
            return response.status(200).json({success: true, boards})
        })
        
    });