반응형

[ 목차 ]

내 사이트가 Netlify에 배포된 이후에도 아직 검색이 안되고 있습니다. 주소가 아니면 아직 접근할 방법이 없네요. 구글에 노출시키는 작업이 필요합니다. 이걸 설정해주는게 구글 서치 콘솔(Google Search Console)입니다. 여기에 등록해주면 구글에서 검색도 되고, 그 외에 모니터링도 가능해집니다. 오늘은 서치 콘솔에 등록하고, sitemap.xml, robots.txt 파일을 적용하는 방법에 대해 알아보겠습니다.

    1.구글 서치콘솔 등록

    구글 서치콘솔에 로그인한 후 속성 추가를 해 줍니다. 

    [ 속성 유형 선택 ]

    다음으로 속성 유형에서 "URL 접두어" 부분으로 가서 추가하고자 하는 URL을 적어주고 "계속" 을 클릭해줍니다.

     

    [ 소유권 확인 ]

    다음으로 소유권 확인창이 뜹니다. 여기서 HTML 태그의 드랍다운 버튼을 누르면 내부에 방법이 나옵니다. meta 태그를 복사후 창을 닫아버리면 안되고, 내 프로젝트로 가서 입력을 해줘야합니다. 

     

    [ 태그 입력 ]

    HTML meta태그여서 vuepress에 그대로 옮겨줄 순 없고, 아래와 같이 config.js파일에 name과 content 속성에 분리해서 입력해줍니다.

    module.exports = {
      title:"Hello, Vuepress",
      head:[
        [
          "meta", 
          {
            name: "google-site-verification",
            content: "본인 코드"
          }
        ]
      ],
    }

     

    [ 소유권 확인 완료 ]

    수정 후 배포가 완료되면 소유권 확인 창에서 "확인" 버튼을 눌러줍니다. 

     

    2. sitemap적용

    sitemap.xml파일을 어딘가에 생성하는게 아니라 플러그인으로 설정합니다. 우선 아래의 명령으로 vuepress용 sitemap 생성 플러그인을 설치합니다.

    npm i -D vuepress-plugin-sitemap

     

    플러그인은 config.js에서 추가해주고, 추가 시 호스트 네임을 적어주면 됩니다.

    module.export = {
    	plugin: [["sitemap", { hostname: "https://unaffected.netlify.com/"}]]
    }

    배포 이후, 구글 서치콘설의 sitemap 제출란에 https://unaffected.netlify.com/sitemap.xml 로 등록하면 됩니다.

     

    3. robots.txt

    웹 크롤러같은 봇들의 접근을 제어하는 파일입니다. 보여줄 수 있는 페이지와 그렇지 않은 페이지를 설정합니다.

    위치는 .vuepress/public/robots.txt입니다.

    User-agent: *
    Allow: /
    Sitemap: https://unaffected.netlify.com/sitemap.xml

    배포 확인은 본인 https://unaffected.netlify.com/robots.txt 에 접속해서 robots.txt파일이 잘 뜨는지 확인해보면 됩니다.

     

     

     

    반응형
    반응형

    Node 18버전에서 vuepress 1.9.9 버전 설치에 오류가 있어서 포기했다가, 다시 Node 16버전으로 낮춰서 설치했습니다. 아직 Beta버전인 2.0.0 보다 오류가 적은 것 같습니다. 설치하니 기본적으로 검색 툴이 활성화되고, Vue 컴포넌트 추가도 components 폴더에 만드니 별다른 설정없이 인식이 됩니다. 그리고 무엇보다도 태그 요소 추가가 너무 쉽게 진행됩니다. Vuepress2로 하려고 시도하며 공부해서인지 금방금방 작성이 되네요. 다시 Vuepress 1으로 재작성해야겠습니다...ㅠㅠ

     

    1. 설치

    npm init
    
    npm i -D vuepress@next

     

    2. ./docs/README.md 파일 생성

    ### Hello Vuepress

     

    3. ./gitignore 파일 생성

    node_modules
    .cache
    .temp
    

     

    4. package.json파일 수정

    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "dev": "vuepress dev docs",  // 추가
        "build": "vuepress build docs"  // 추가
      },
    

     

    5. 실행

    npm run dev

     

    6. 구조

    .
    ├── docs
    │   ├── .vuepress (Optional)
    │   │   ├── components (Optional)
    │   │   ├── theme (Optional)
    │   │   │   └── Layout.vue
    │   │   ├── public (Optional)
    │   │   ├── styles (Optional)
    │   │   │   ├── index.styl
    │   │   │   └── palette.styl
    │   │   ├── templates (Optional, Danger Zone)
    │   │   │   ├── dev.html
    │   │   │   └── ssr.html
    │   │   ├── config.js (Optional)
    │   │   └── enhanceApp.js (Optional)
    │   │ 
    │   ├── README.md
    │   ├── guide
    │   │   └── README.md
    │   └── config.md
    │ 
    └── package.json
    

     

    7. docs/.vuepress/config.js

    화면구성 참조용으로 제가 작업했던 내용 공유해놓겠습니다.

    module.exports = {
      title:"Hello, Vuepress",
      themeConfig: {
        logo: '/assets/img/logo.png',
        nav: [
          { text: 'Home', link: '/' },
          { text: 'Guide', link: '/guide/' },
          { text: 'External', link: 'https://google.com' }
        ],
        sidebar: [
          {
            title: 'Today I Learned',  // required
            path: '/foo/',      // optional, link of the title, which should be an absolute path and must exist
            collapsable: false, // optional, defaults to true
            sidebarDepth: 1,    // optional, defaults to 1
            children: [
              {title: '1 설치(v2)',path:'/pages/1_설치.md'}, 
              {title: '2 레이아웃(v2)',path: '/pages/2_레이아웃.md'},
              {title: '3 검색창(v2)',path: '/pages/3_검색창.md'},
              {title: '4 Vue컴포넌트(v2)',path: '/pages/4_Vue컴포넌트.md'},
              {title: '5 태그(v2)',path: '/pages/5_태그.md'},
              {title: '6 vuepress v1설치',path: '/pages/6_v1설치.md'}
            ],
          },
          {
            title: 'Group 2',
            children: [ /* ... */ ],
            initialOpenGroupIndex: -1 // optional, defaults to 0, defines the index of initially opened subgroup
          }
        ]
      }
    }

     

    8. 태그 리스트 컴포넌트 만들기

    태그 리스트 컴포넌트를 생성 후 README.md에서 확인해보겠습니다.

     

    docs/.vuepress/components/TagList.vue

    <template>
      <div class="tag-list">
        <h3>Tags :</h3>
        {{ tags }}
      </div>
    </template>
    
    <script>
    export default {
      computed:{
        tags() {
          // 모든 태그를 가져옵니다.
          const tagSet = new Set()
          this.$site.pages.forEach(page => {
            if (page.frontmatter.tags) {
              page.frontmatter.tags.forEach(tag => {
                tagSet.add(tag)
              })
            }
          })
          return [...tagSet].sort()
        }
      }
    }
    </script>

     

    9. README.md

    대쉬 3개(---) 사이에 적어놓은 부분을 frontmatter라고 합니다. 이 부분은 해당 md파일의 주요 정보들을 적어놓는 용도로 사용하는데, docs폴더 내부에 테스트를 위해 몇가지 md파일들을 생성해놓고 아래와 유사하게 frontmatter를 작성해둡니다. tags에 1.js, 2.js 등 여러가지 키워드를 넣었습니다.

    ---
    title: 'Vuepress2 태그시스템'
    date: '2023-07-06'
    tags:
      - JavaScript
      - 2.js
    ---
    
    # KMS Data 검색 속도 건 관련
    
    이 문서에서 사용하는 태그 목록을 출력합니다.
    <!-- {{ $site }} -->
    
    <TagList />

     

    <결과>

    반응형
    반응형

    1. 플러그인 추가

    npm i -D @vuepress/plugin-register-components@next

     

    2. .vuepress/config.js파일에 플러그인 추가

    import { registerComponentsPlugin } from '@vuepress/plugin-register-components'
    import { getDirname, path } from '@vuepress/utils'
    
    // const __dirname = getDirname(import.meta.url)  // 인식 오류시 사용
    
    export default {
      title:"Hello, Vuepress",
      plugins: [
        registerComponentsPlugin({
          componentsDir: path.resolve(__dirname, './components'),   // 컴포넌트 폴더를 등록하는 방법
          // components:{
          //   TagList: path.resolve(__dirname, './components/TagList.vue'),   // 개별 컴포넌트를 등록하는 방법
          //   MyComponent: path.resolve(__dirname, './components/MyComponent.vue'),   // 개별 컴포넌트를 등록하는 방법
          // } 
        })
      ],
    }

    참고로 현재 등록하고자 하는 파일은 아래의 파일입니다.

    <!-- docs/.vuepress/components/MyComponent.vue -->
    <template>
      <div>
        <p>Component Test</p>
      </div>
    </template>
    
    <script>
    export default {
      name: 'MyComponent'
    }
    </script>

     

    3. .vuepress/clientAppEnhance.js 생성

    아래도 컴포넌트를 등록해줍니다. 원래대로라면 플러그인에 의한 방법, clientAppEnhance.js로 등록하는 방법으로 나뉠 수 있는데, 저는 등록이 안되어 같이 적용해주니 작동되었습니다.

    // .vuepress/clientAppEnhance.js
    
    import MyComponent from './components/MyComponent.vue';
    
    export default ({ app }) => {
      app.component(MyComponent.name, MyComponent);
    };

     

    4. README.md파일에 적용

    <MyComponent />

    반응형
    반응형

    [ 목차 ]

      블로그 같은걸 만들다보니 순수 Vue.js보다는 SSR 또는 정적 사이트 생성기 SSG가 필요하게 되었습니다. React에는 유명한 Gatsby가, 그 이전에 Ruby에는 Jekyll 이라는 정적 사이트가 있었는데, Vue에는 마땅한게 없나 살펴보던 중 Vuepress 라는 걸 알게되었습니다. 오늘은 Vuepress를 이용하여 간단한 블로그를 생성해보겠습니다.

       

      Vuepress2 

       

      Home | VuePress

       

      v2.vuepress.vuejs.org

       

       

       

      1. 설치

      설치는 npm으로 간단히 아래와 같이 진행하면 됩니다.

      npm init
      
      npm install -D vuepress@next

       

      2. 구성

      처음 라이브러리를 설치하면 위 이미지처럼 아무것도 나타나지 않습니다. 여기에 몇가지 수동으로 폴더 및 파일을 생성해줘야합니다.

      1) 우선 docs라는 폴더를 만들고 내부에 README.md파일을 만들어줍니다. 그리고 내용은 적당히 아래와 같이 넣어줍니다.

      # Hello Vuepress

      2) package.json에 실행하기 위한 아래의 스크립트를 넣어줍니다.

      "scripts": {
          "test": "echo \"Error: no test specified\" && exit 1",
          "dev": "vuepress dev docs",  // 추가
          "build": "vuepress build docs"  // 추가
        },

      3) "npm run dev"를 실행해줍니다. 그러면 docs 아래에 .vuepress폴더 및 하위 구성이 생성됩니다.

      4) .gitignore파일을 생성해줍니다. (optional, 나중에 github에 올릴때 불필요한 부분을 제거하기 위해...)

      node_modules
      .temp
      .cache

       

      3. 실행/확인

      실행하여 화면을 확인해봅니다.

      npm run dev

      드디어 나왔습니다. 보이는 것처럼 우리가 작성한 각각의 markdown파일이 하나의 화면으로 구성되어 나타납니다.

       

      4. 내비게이션 바 (nav bar ) / 사이드바 (sidebar) 추가

      테마 / 레이아웃 등은 config.js파일에서 수정할 수 있습니다. .vuepress폴더 아래 config.js파일을 생성하고 아래의 코드를 넣어줍니다. 기본적인 navbar와 sidebar 구성만 추가해보겠습니다. 

      import { defaultTheme } from '@vuepress/theme-default'
      
      export default {
        title:"Hello, Vuepress",
        theme: defaultTheme({
          sidebar:[
            {
              text: 'Group',
              children: [
                {
                  text: 'SubGroup',
                  children: ['/group/foo.md', '/group/bar.md'],
                },
              ],
            }
          ],
          navbar: [
            // nested group - max depth is 2
            {
              text: 'Group',
              children: [
                {
                  // text: 'SubGroup',
                  children: ['/group/foo.md', '/group/bar.md'],
                },
              ],
            },
            // control when should the item be active
            {
              text: 'Group 2',
              children: [
                {
                  text: 'Always active',
                  link: '/',
                  // this item will always be active
                  activeMatch: '/',
                },
                {
                  text: 'Active on /foo/',
                  link: '/not-foo/',
                  // this item will be active when current route path starts with /foo/
                  // regular expression is supported
                  activeMatch: '^/foo/',
                },
              ],
            },
          ],
        }),
      }

      반응형
      반응형

      서버리스 앱 만들기의 마지막 단원으로 Vue.js 프론트 앱을 배포해보도록 하겠습니다. 

       

      1. 앱 만들기

      Vue 앱을 만들어줍니다.

      vue create node_post_vue .    // .을 찍으면 현재 폴더에 프로젝트를 생성합니다.
      
      vue add router  // 곧바로 router 라이브러리를 함께 설치해줍니다.

       

      필요한 라이브러리를 아래와 같이 설치해줍니다.

      npm i vuex axios

      간단히 백엔드에서 보내오는 데이터를 읽어다 표현해주는 것만 할건데도 Store를 구성하고 각 컴포넌트에서 Store state를 이용해야하는게 좀 불편해 보이네요. 그래도 한번만 세팅해놓으면 다음부터는 비교적? 편하게 작업을 할 수 있다고 생각하고 진행하셔요^^;;

       

       (1) ./src/main.js

      import { createApp } from 'vue'
      import App from './App.vue'
      import router from './router'
      import {store} from './store/store.js'
      
      createApp(App)
      .use(router)
      .use(store)
      .mount('#app')

       

      (2) ./src/App.vue

      <template>
        <router-view/>
      </template>
      
      <style>
      #app {
        font-family: Avenir, Helvetica, Arial, sans-serif;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
        text-align: center;
        color: #2c3e50;
      }
      </style>

       

       (3) ./src/router/index.js

      import { createRouter, createWebHistory } from 'vue-router'
      import HomeView from '../views/HomeView.vue'
      
      const routes = [
        {
          path: '/',
          name: 'home',
          component: HomeView
        }
      ]
      
      const router = createRouter({
        history: createWebHistory(process.env.BASE_URL),
        routes
      })
      
      export default router

       

        (4) ./src/components/HelloWorld.vue

      <template>
        <div class="hello">    
          <ul>
            <li class="post" v-for="post in postlist" :key=post>
              <div class="title">
                {{ post.title }} 
              </div>
              <div class="content">
                {{ post.content }} 
              </div>
              <div class="lower">
                <div>...by {{ post.creator }} </div>
                <div>on {{ post.publish_date.split('T')[0] }}</div>
              </div>
            </li>
          </ul>
        </div>
      </template>
      
      <script scoped>
      export default {
        name: 'HelloWorld',
        props: {
          msg: String
        },
        computed:{
          postlist(){            
            return this.$store.state.posts;
          },    
        },
        created(){
            this.$store.dispatch('onLoad');
          }
      }
      </script>
      
      <!-- Add "scoped" attribute to limit CSS to this component only -->
      <style scoped>
      ul {
        text-align: center;
        list-style-type: none;
        margin: 0 auto;
        padding: 0;
        width: 800px;
      }
      .post {
        /* display: inline-block; */
        margin: 10px 10px;  
        border: 1px solid #42b983;
        border-radius: 15px;
        padding: 8px;
      }
      
      .post .title{
        text-align: left;
        font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
        font-size:larger;
        font-weight: 900;
        color:#222;
      }
      .post .content{
        text-align: left;
        font-size:small;
        padding: 5px;
        height: 80px;
        color:#999;
      }
      .post .lower{
        text-align: right;
        color:grey;
        font-size:small
      }
      a {
        color: #42b983;
      }
      </style>

       

        (5) ./src/store/store.js

      import { createStore } from 'vuex';
      import axios from 'axios';
      
      axios.defaults.baseURL = 'https://vmsahpyntz.eu10.qoddiapp.com';
      axios.defaults.headers.post['Content-Type']='application/json;charset=utf-8';
      axios.defaults.headers.post['Access-Control-Allow-Origin']='*';
      
      export const store = createStore({
        state:{
          posts:[]
        },
        mutations:{
          updateState(state, payload){
            Object.keys(payload).forEach((key) => {
              state[key] = payload[key];
            });
          }
        },
        actions:{
          async onLoad(context){
            const res= await axios.get('/');
            const post = res.data;
            // console.log(res);
            
            context.commit('updateState',{
              posts:[...context.state.posts, ...post],
            })
          },
        }
      });

       

      2. gitlab에 배포하기

      저는 회사 특성상 github 접근이 불가능해서 gitlab을 주로 사용합니다. 사용 방법은 github과 동일합니다.

      git remote add origin [gitlab주소: 대활호 빼고]
      git pull origin main
      git add .
      git commit -m "initial commit"
      git push origin main // main인지 master인지 본인의 branch를 잘 확인하고 진행합니다.

       

      3. Netlify에서 연동하기

      Netlify에 접속해줍니다. 계정이 없다면 적당한 방법으로 계정을 생성해주셔요.

      "Sites  >  Add new site  >  Import an existing project"를 클릭해줍니다.

      아래 그림에서 본인의 저장소가 있는 곳을 선택합니다. 저는 Gitlab

       

      본인의 프로젝트를 선택합니다.

       

      배포 세팅을 하게 되됩니다. 배포할 브랜치, 빌드 명령어(npm run build), 배포 디렉토리(일반적으로 /dist) 를 확인하고, 아래에 Deploy Site를 눌러주면 배포가 시작됩니다.

       

      배포가 완료되면 아래와 같이 화면이 변경되며, 배포된 url이 표시가 됩니다. 

       

      해당 링크를 클릭하면 우리가 만든 사이트가 나타납니다.

       

      이제 수정사항이 생길때마다 Gitlab으로 배포만 하면 자동으로 Netlify도 업데이트됩니다. 

      지금까지 DB, Backend 서버, Frontend 서버를 모두 서버리스로 구현해보았습니다.

       

      ~~~끝~~~~

      반응형
      반응형

      제목이 참 힘드네요...

       

      데이터는 적당히 입력이 되었다고 하면, Node(Express)를 통해서 데이터를 넘겨주는 서버를 만들어보겠습니다.

      1 .env 파일

      CockroachDB연결정보는 사이트에서 제공하는 connection string을 그대로 붙이는게 편리합니다. 비밀번호도 찾아서 잘 넣어주시구요.

      PORT=3000
      NODE_ENV='development'
      SECRET=mysecretkeytest
      COCKROACHDB_CONNECT_URL='postgresql://<유저아이디>:<비밀번호>@wind-raccoon-4725.8nk.cockroachlabs.cloud:26257/defaultdb?sslmode=verify-full'

       

      2. postRoute.js

      Connection String에 정의된대로 연결하니 오히려 더 깔끔한 것 같네요.

      import express from 'express';
      import pg from 'pg';
      import dotenv from 'dotenv';
      import bodyParser from 'body-parser'
      
      dotenv.config();
      const { COCKROACHDB_CONNECT_URL } = process.env;
      
      const router = express.Router();
      router.use(express.json());
      
      const client = new pg.Client(COCKROACHDB_CONNECT_URL);
      
      client.connect(err => {
        if (err) {
          console.error('connection error', err.stack)
        } else {
        	console.log('success!')
        }
      });
      
      
      // 전체 리스트 읽기
      router.get('/', (req, res) => {
        // res.send('hello');
        const query = new pg.Query("SELECT * FROM MEMO_POST");
        client.query(query);
      
        var rows = [];
        /** 
         *  row에서 데이터 가져오고 end에서 검색할 때 발생한 각종 정보, error는 오류 발생시
         */
        query.on("row",row=>{
          rows.push(row);
        });
        query.on('end', () => {
          console.log(rows);
          console.log('query done')    
          res.send(rows);
          res.status(200).end();
        });
        query.on('error', err => {
          console.error(err.stack)
        });
      });

       

      3. index.js

      구동을 위해 index.js의 소스코드도 올려둡니다.

      import express from 'express';
      import session from 'express-session';
      import cookieParser from 'cookie-parser';
      import dotenv from 'dotenv';
      import cors from 'cors';
      
      // import mongoose from 'mongoose';
      // import auth from './routes/auth.js';
      import postRoute from './routes/postRoute.js';
      
      dotenv.config();
      
      const app = express();
      
      const { PORT, SECRET } = process.env;
      app.set('port', PORT || 3000);
      
      app.use(express.json());
      app.use(express.static('public'));
      app.use(express.urlencoded({ extended: true }));
      app.use(cookieParser(SECRET));
      app.use(session({
          resave: false,
          saveUninitialized: false,
          secret: SECRET,
          cookie: {
              httpOnly: true,
              secure: false
          }
      }));
      
      app.use(cors());  // 이걸로는 잘 안됨
      app.all('/*', function(req, res, next){
        res.header("Access-Control-Allow-Origin", "*");
        res.header("Access-Control-Allow-Headers", "X-Requested-With");
        next();
      })
      
      app.use('/', postRoute);
      
      app.listen(app.get('port'), ()=> {
        console.log(`http://localhost:${app.get('port')} 번 포트에서 서버 실행 중..`);
      });

       

      결과가 잘 나오네요^^

       

      반응형
      반응형

      모든 서비스 클라우드에서 구동하기를 해보려고, 이번엔 Database를 찾고 있습니다. 이번에도 역시 무료가 어느정도 가능한 서비스를 찾다보니 CockroachDB라는 것을 찾게 되었습니다.

       

       

      Cockroach Labs, the company building CockroachDB

       

      Cockroach Labs, the company building CockroachDB

      CockroachDB is a distributed database with standard SQL for cloud applications. CockroachDB powers companies like Comcast, Lush, and Bose.

      www.cockroachlabs.com

       

      Cockroach라면 우리말로 바퀴벌레인데요, 단어를 알게되는 순간 이미지가 급 안좋아지는데 이 또한 의미가 있다고 하네요. 뭐냐하면 CockroachDB는 시스템에 크고 작은 문제가 생겼을 때 생존하고 스스로 회복하는 것 (Resiliency) 에 가장 큰 강점을 두고 있다고 합니다. 분산 시스템을 설계할 때에 가장 어려운 문제 중 하나가 바로 장애 상황에서 일관성이나 가용성을 최대한 유지하면서 복구해내는 것인데요. 특히 분산 데이터베이스 시스템의 경우 복구에 많은 시간이 걸리거나 많은 데이터가 소실되면 어플리케이션에 큰 영향을 끼칠 수 있습니다.

       

      CockroachDB의 경우 디스크, 물리적 머신, 심지어 데이터 센터 단위의 장애가 생기더라도 생존할 수 있는 다양한 옵션을 제공하고 있습니다. 또한 문제 상황이 생기면 스스로 감지하고 사람의 개입 없이도 자동으로 서비스를 최대한 복구해냅니다. 정말 계속해서 나타나는 바퀴벌레의 생명력이 생각나네요. 계속해서 잘 살아남이 DB를 유지해주길 바래봅니다.

       

      가격정책을 보니까 제가 좋아하는 무료정책이 있습니다. 기간이 나와있지는 않는데, 10GiB의 스토리지와 월 50M 건의 요청 안에서 사용할 시 무료인 것으로 보입니다. 

       

      가입과정을 거쳐 진입하면 자체 콘솔화면이 나타납니다. 여기서 우측 상단에 보이는 Create Cluster를 눌러 생성을 시작합니다.

       

      다음으로는 Serverless 플랜을 선택합니다. 그리고 아래쪽에 "Start for free"를 눌러 다음을 진행해줍니다. 지금 저는 하나의 무료 cluster를 이미 생성했기 때문에 해당 메뉴가 활성화가 안되네요.

       

      제 화면은 아니지만 아래와 같이 Cluster name이 적당히 생성되고, 다음 오른쪽 보라색 생성버튼을 눌러줍니다. 

       

      생성되면 접속과 관련된 정보들이 나타납니다. 이 정보는 터미널에서 직접 DB를 관리할 때 필요한 것 같습니다. DBeaver같은 데이터베이스 관리도구를 사용하면 3번의 접속정보 정도만 알아도 사용 가능합니다. 중간에 Database이름, 사용자 이름과 비밀번호를 생성하는 부분이 있는데, 1번만 알려준다고 하니 잊어버리지 않도록 주의하시기 바랍니다. 잊어버리면 새로 생성할 수는 있습니다.

       

      아래와 같이 host, port, database, username, password 등 접속정보를 넣고 입력하면 접속이 됩니다.

       

      이제 웹상에 데이터 저장이 가능한 내 Postgresql DB가 생성되었습니다. 

       

      아래와 같이 입력하여 신규 Table을 생성하고, 데이터를 집어넣어봅시다.

      CREATE TABLE MEMO_POST (
      	POST_ID integer generated by default as identity,
      	TITLE VARCHAR(50),
      	CONTENT VARCHAR(50),
      	CREATOR VARCHAR(10) ,
      	PUBLISH_DATE TIMESTAMP 
      );
      
      insert into memo_post values (default,'첫번째포스팅','안녕하세요, 포스팅 테스트1 입니다.', 'wilkyway', CURRENT_TIMESTAMP);
      insert into memo_post values (default,'두번째포스팅','안녕하세요, 포스팅 테스트2 입니다.', 'wilkyway', CURRENT_TIMESTAMP);
      insert into memo_post values (default,'세번째포스팅','안녕하세요, 포스팅 테스트3 입니다.', 'wilkyway', CURRENT_TIMESTAMP);
      
      select * from memo_post

       

      조금 실수가 있어서 첫번째 라인이 지워졌지만.... 데이터 잘 입력되고 확인이 되네요^^

      반응형
      반응형

      1. store/store.js 수정
      store.js 파일에 url request가 가능하도록 각 기능마다 axios 기능을 추가해줍니다. 아울러, 최초 Load시에는 DB의 정보들을 불러올 수 있도록 onLoad함수를 추가해주었습니다.

      import { createStore } from 'vuex';
      import axios from 'axios';
      
      axios.defaults.baseURL = 'http://localhost:3000';
      axios.defaults.headers.post['Content-Type']='application/json;charset=utf-8';
      axios.defaults.headers.post['Access-Control-Allow-Origin']='*';
      
      export const store = createStore({
      // export default createStore({
        state:{
          user:{
            // {username: '홍길동', email: 'abcd@abcd.com', password: '1234'}
          },
          posts: [
            // {_id: '1', title: 'apple', body: 'Im apple', creator: 'apple'},
            // {_id: '2', title: 'banana', body: 'Im banana', creator: 'banana'},
            // {_id: '3', title: 'orange', body: 'Im orange', creator: 'orange'}
          ]
        },
        mutations:{
          updateState(state, payload) {
            Object.keys(payload).forEach((key) => {
              state[key] = payload[key];        
            });
          },
          LOGIN(state, payload){
            state.user = payload;
          },
          DELETEPOST(state, post_id){            
            const delete_index = state.posts.findIndex(p=> p._id === post_id);      // 삭제할 포스트의 index 찾기
            state.posts.splice(delete_index,1);      
          },
          UPDATEPOST(state,updatePost){      
            const update_store_item = state.posts.find(p => p._id === updatePost._id);      
            // console.log(updatePost)
            update_store_item.title = updatePost.title;
            update_store_item.body = updatePost.body;
          }
        },
        actions:{ 
          async login(context, name){            
            const res = await axios.post('/auth/register',name);      
            context.commit('LOGIN', res.data);
          },  
          async onLoad(context){
            const res = await axios.get('/posts');
            const { post } = res.data;
            console.log(post);
            context.commit("updateState", {
              posts: [...context.state.posts, ...post],
            })
          },
          async addPost(context, newPost){
            // const id= context.state.posts.length+1;      
            // const post={
            //   _id: id,
            //   title: newPost.title,
            //   body: newPost.body,
            //   creator: newPost.title
            // }
            const res = await axios.post('/posts', newPost);
            const post = res.data;  
            context.commit("updateState", {
              posts: [...context.state.posts, post],
            })         
          },
          async deletePost(context, post_id){
            await axios.delete(`/posts/${post_id}`);  
            context.commit("DELETEPOST", post_id);
          } ,
          async updatePost(context, updatePost){
            const { _id } = updatePost;
            await axios.patch(`/posts/${_id}`, updatePost);
            context.commit("UPDATEPOST", updatePost)
          }    
        }
      });

       
      2. view/HomeView.vue 수정
      유저가 존재할 경우와 존재하지 않을 경우를 구분하여 표시하도록 파일을 수정해줍니다.

      <template>
        <div class="logincheck">
          <div v-if="isloggedin">안녕하세요, {{ user.username }}님</div>    
          <router-link to="/kakaologin" v-else>Kakao Login</router-link>
        </div> 
        <h1 class="appname">My Todo App</h1>  
        <AddPost />
        <ListofPost />
      </template>
      
      <script>
      import ListofPost from '../components/ListofPost.vue'
      import AddPost from '../components/AddPost.vue'
      
      export default {
        name: 'HomeView',
        components: {
          ListofPost,
          AddPost,
        },
        computed:{
          user(){
            return this.$store.state.user
          },
          isloggedin(){
            return this.$store.state.user.username? true : false;
          }
        }
      }
      </script>
      
      <style>
      #app {
        font-family: Avenir, Helvetica, Arial, sans-serif;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;  
        color: #2c3e50;
        margin-top: 60px;  
      }
      .appname {
        color:#373738;
        text-align: center;
      }
      .addbutton{
        margin: auto;
        display:flex;
        align-items:center;
        justify-content: center;
        width:50px;
        height:50px;  
        border-radius: 50%;
        background-color:blue ; 
        font-size: 36px;
        font-weight: bold;
        color:beige;
      }
      .logincheck{  
        text-align: right;  
        margin-right: 15px;
      }
      </style>

       
      3. components/ListofPost.vue 수정
      최초 로딩시 DB 데이터를 불러오도록 onLoad 함수를 호출합니다.

      <template>
        <ul>
          <li v-for="post in posts.slice().reverse()" :key=post>
            <EachofPost 
              :id=post._id
              :titleOfPost=post.title 
              :bodyOfPost=post.body 
              :creator=post.creator />
          </li>
        </ul>
      </template>
      <script>
      import EachofPost from './EachofPost.vue'
      
      export default {
        name: 'ListofPost',
        components: {
          EachofPost,
        },
        computed:{
          posts(){
            return this.$store.state.posts;
          },    
        }, 
        created(){
            this.$store.dispatch('onLoad');  // 추가
        }
      }
      </script>
      
      <style>
      ul{
        padding-left:0;
      }
      li{
        list-style: none;
      }
      </style>

       

      반응형

      + Recent posts