조회수 증가, 게시글 조회, 게시글 작성, form

keep_going·2022년 12월 20일
0

vue

목록 보기
2/13
글목록 GET => http://1.234.5.158:23000/board101/select.json?page=1&text=
글쓰기 POST => http://1.234.5.158:23000/board101/insert.json  => key 정보 : title, content, writer
글수정 PUT => http://1.234.5.158:23000/board101/update.json?no=113 => key 정보 : title, content, writer
글삭제 DELETE => http://1.234.5.158:23000/board101/delete.json?no=1131개조회 GET => http://1.234.5.158:23000/board101/selectone.json?no=668
조회수증가 PUT => http://1.234.5.158:23000/board101/updatehit.json?no=668

------------------------------------------------------

await axios.get(url, {headers});
await axios.post(url, body, {headers});
await axios.put(url, body, {headers});
await axios.delete(url, {headers:headers, data:body});

// 파일명 : vue.config.js
// 변경시 반드시 서버 재구동!!!

// npm run serve => 호출할때만 읽어서 수행함. 호출 후 수정했으면 재호출해야 수정된 내용이 반영된다.
// 환경 설정파일은 서버를 재구동해야해!
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,

  devServer :{
    //벡엔드 서버 위치 : 프론트에서 '/board101로 시작하면 실제로는 target에 있는 주소를 앞에 붙여서 시행하라는 뜻
    proxy : {
      '/board101' : {
        target : 'http://1.234.5.158:23000',
        changeOrigin : true,
        logLevel:'debug'
      }
    }
  }
})


*** package.json, package-lock.json파일이 있는 위치에서 실행

CMD> npm run serve


// 파일명 : routes/index.js

// cmd에서 설치한 라이브러리를 가져와서 적용
import { createWebHistory, createRouter  } from 'vue-router';

// 내가 만든 컴포넌트 가져오기
import HomePage from '@/components/HomePage.vue';
import LoginPage from '@/components/LoginPage.vue';
import JoinPage from '@/components/JoinPage.vue';
import BoardPage from '@/components/BoardPage.vue';
import BoardContentPage from '@/components/BoardContentPage.vue';

// [{},{},{},{},{}] 자바스크립트 이므로 배열형태 인것.
const routes = [
    {path :"/", component:HomePage },
    {path :"/login", component:LoginPage },
    {path :"/join", component:JoinPage },
    {path :"/board", component:BoardPage },
    {path :"/boardcontent", component:BoardContentPage },
    // {path :"/boardinsert", component:BoardInsertPage },
];

const router = createRouter({
    history : createWebHistory(),
    routes : routes
});

export default router;

// 파일명 : BoardPage.vue

<template>
    <div>

        <router-link to='/boardinsert'>
            <button>글쓰기1</button>
        </router-link>
		// :(콜론)을 찍으면 object로 query를 보낼 수 있다. 위와 아래는 같은 역할을 수행하지만 아래를 기억하는게 더 유용!
        <router-link :to="{path:'/boardinsert', query:{no:1}}">
            <button>글쓰기2</button>
        </router-link>
        
        <table border="1">
            <thead>
                <tr>
                    <th>번호</th>
                    <th>제목</th>
                    <th>작성자</th>
                    <th>조회수</th>
                    <th>날짜</th>
                </tr>
            </thead>
            <tbody>
                <tr v-for="tmp of board.rows" :key="tmp">
                    <td>{{ tmp._id }}</td>
                    <td @click="handleContent( tmp._id )" style="cursor:pointer;">{{ tmp.title }}</td>
					// 클릭 가능 한 것처럼 손가락 형태로 커서 모양 변경
					// a 태그를 쓰면 html과 똑같이 엔터를 치면 깜박인다. vue를 쓸 이유가 없다! 컴포넌트만 바꾸려면 router사용
					// 주소를 바꾸는 이유? 컴포넌트만 교체하는거라 의미 없지만 새로고침했을때 페이지를 유지하기 위해서 필요
                    <td>{{ tmp.writer }}</td>
                    <td>{{ tmp.hit }}</td>
                    <td>{{ tmp.regdate }}</td>
                </tr>
            </tbody>
        </table>
    </div>
</template>

<script>
import { reactive, onMounted } from 'vue';
import axios from 'axios';
import { useRouter } from 'vue-router';


export default {
    setup () {
        const router = useRouter();
      	// 이동은 router 사용. import 시켜야함.

        // 상태 변수
        // 목록 => [{},{}...{}]
        const board = reactive({
            rows : [
                {_id:1, title:'a', writer:'b', hit:1, regdate:'2022'},
                {_id:2, title:'a', writer:'b', hit:1, regdate:'2022'},
                {_id:3, title:'a', writer:'b', hit:1, regdate:'2022'},
            ]
        });

        const handleContent = async ( tmp ) => {
        //위에서 tmp._id로 받은값을 tmp로 받음
            console.log('handleContent');

            // 조회수를 증가시키고 성공하면
            const url = `/board101/updatehit.json?no=${tmp}`;
            const headers = {"Content-Type":"application/json"};
            const {data} = await axios.put(url, {}, {headers});
          	// body가 비었을때
            console.log(data);

            if( data.status === 200 ) {
                // 주소창을 바꾸고, 컴포넌트 교체, 리로딩 아님!!!
                // localhost:8080/boardcontent?no=tmp로 받은값
                router.push({path:'/boardcontent', query:{no:tmp}});
            }
        }
        

        const handleData = async() => {
            const url      = `/board101/select.json?page=1&text=`;
            const headers  = {"Content-Type":"application/json"};
            const { data } = await axios.get(url, {headers});
            console.log(data);

            // 정상적인 데이터인지 확인
            if(data.status === 200){
                // 테이블을 그리기 위한 상태변수에 값을 추가!!
                board.rows = data.rows;
            }
        }

        // 페이지가 로딩될때 자동 실행되는 함수
        onMounted(() => {
            handleData(); //벡엔드에서 게시판 목록 받아오기
        });
        // 외부에서 사용하지 않는다면 return 필요 없다!
        return {
            board,
            handleContent
        };
    }
}
</script>

<style lang="css" scoped>

</style>

// 파일명 : BoardContentPage.vue

<template>
    <div>
        <h3>게시판 상세 내용</h3>
        {{  state  }}

        <p>번호 : {{ state.row._id }}</p>
        <p>제목 : {{ state.row.title }}</p>

        <button @click="handleBack()">이전</button>
    </div>
</template>

<script>
import router from '@/routes';
import axios from 'axios';
import { reactive, onMounted } from 'vue';
import { useRoute } from 'vue-router';

export default {
    setup () {
      	// BoardPage에서 보낸 no를 받기 위함. import 필요!
      	// 보내는건 router, 받는건 route
        const route = useRoute();
        
        // ?no=771
        const state = reactive({
            no : Number(route.query.no),
          	// BoardPage에서 query:{no:tmp}로 보낸 no값을 state.no로 받는것!
            row : '',
        });

        const handleData = async() => {
            const url = `/board101/selectone.json?no=${state.no}`;
            const headers = {"Content-Type":"application/json"};
            const { data } = await axios.get(url, {headers});
            console.log(data);

            if( data.status === 200 ) {
                state.row = data.result;
            }
        };

        // 웹페이지 생명주기 화면이 로딩될때 자동 실행
        onMounted(() => {
            handleData();
        });


        // 이전페이지 이동            
        const handleBack = () =>{
            router.go(-1);
        };

        return {
            state, 
            handleBack
        }
    }
}
</script>

<style lang="css" scoped>

</style>

// 파일명 : BoardInsertPage.vue

<template>
    <div class="container">
        <h3>게시판 글쓰기</h3>
        <hr />
        {{ state }}
        <div class="item">
            <label class="lbl">제목</label>
            <input type="text" v-model="title" />
            <!-- return에서 toRefs로 하면 state.title을 title로 써도 됨! -->
        </div>

        <div class="item">
            <label class="lbl">작성자</label>
            <input type="text" v-model="writer" />
        </div>

        <div class="item">
            <label class="lbl">내용</label>
            <textarea rows="6" cols="22" style="resize: none;" v-model="content"></textarea>
        </div>

        <div class="item">
            <label class="lbl"></label>
            <button @click="handleInsert()">글쓰기</button>
        </div>

    </div>
</template>

<script>
import { reactive, toRefs } from 'vue';
import axios from 'axios';
import { useRouter } from 'vue-router';

export default {
    setup () {
        const router = useRouter(); 

        // 상태 변수
        const state = reactive({
            title   : '',
            content : '',
            writer  : ''
        });
        
        const handleInsert = async() => {
            const url = '/board101/insert.json' ;
            const headers = {"Content-Type":"application/json"} ;
            const body = {
                title   : state.title,
                content : state.content,
                writer  : state.writer
            };
            const { data } = await axios.post( url, body, {headers} )
            console.log(data);

            if(data.status === 200 ) {
                alert('글쓰기 성공!');
                // 목록페이지로 이동하기
                router.push({path:'/board'});
                // <router-link to='/board'></router-link> 이건 a태그의 역할. 클릭해야 이동하는것
                // router.push({path:'/board', query:{}})는 location.href역할. 차이는 리로딩 하지 않고 컴포넌트만 교체 한다는것.
            }
        }

        return {
            state, 
            ... toRefs(state),
            handleInsert
        }  
    }
}
</script>

<style lang="css" scoped>
    .container{
        width   : 600px;
        margin  : 0px auto;
        border  : 3px solid #e6ffef;
        padding : 20px;
    }
    .item {
        margin  : 10px;
    }
    .lbl {
        display : inline-block;
        width   : 100px;
    }

</style>

// 파일명:FormPage.js

<template>
    <div>
        {{ state }}
        <h3>form 실습</h3>

        <input type="text" :value="state.value" /><br />
        // 문자 그대로 출력
        <p>{{ state.value }}</p>
        <p v-text="state.value"></p>
		// 문자 그대로 출력
        <p v-html="state.value"></p>
		// 태그가 해석 되서 출력

        <hr />
        
        <input type="checkbox" value="A" /> A
		// checkbox 일일히 쓰지 말고 반복물 돌림. 4번 반복됨
        <div v-for="tmp of checklist" :key="tmp" style="display: inline-block;">
            <input type="checkbox" :value="tmp.value" v-model="state.check"/>{{ tmp.value }}
            // : (콜론) 빠지니까 모든 값이 하나로 묶여서 체크됨... 왜그랬을까?
            // 원래 <input type="checkbox" value="A" /> A 꼴
            // div에 v-for걸었으니 div 문단이 4번 반복된것!!!!!
        </div>
		<hr />

        <select v-model="state.select">
            <option v-for="tmp of checklist" :key="tmp" :value="tmp.value">{{ tmp.value }}</option>
        </select>
		<hr />
               
        <select v-model="state.select1" multiple> 
         // multiple로 여러개 선택할 수 있게 옵션 준것. ctrl 키로 여러개 선택가능
            <option v-for="tmp of checklist" :key="tmp" :value="tmp.value">{{ tmp.value }}</option>
        </select> 
        <hr />

        <div v-for="tmp of checklist" :key="tmp" style="display: inline-block;">
            <input type="radio" :value="tmp.value" v-model="state.radio"/>{{ tmp.value }}
            // 왜 name으로 안묶어도 되지?
        </div> 
        <hr />

    </div>
</template>

<script>

import { reactive } from 'vue';

export default {
    setup() {
        // 읽기 [{},{},{},{}]
        const checklist = [
            { value: "A" },
            { value: "B" },
            { value: "C" },
            { value: "D" },
        ];

        // 상태 변수(읽고 쓰기) -> v-model을 사용해서 사용자가 입력한 값 실시간으로 받아서 백엔드로 보내면 된다!
       // 위에 {{ state }}로 실시간으로 입력 되는 값 확인 가능
        const state = reactive({
            value: "<p>태그</p>",
            check: ['B'], // 체크박스용 여러개 값 보관
          	// 미리 체크 해 놓고 싶은 값 입력. 없으면 전부 체크 안되있음.
            select : '', // ''는 하나의 값 보관
            select1 : [] , // []는 여러개 값 보관
            radio   : '', //라디오 용 하나의 값 보관
        });
        return {
            state,
            checklist
        };
    },

}
</script>

<style lang="css" scoped>

</style>

그밖에

  • <input type="checkbox" :value="tmp.value" v-model="state.check"/>{{ tmp.value }}
                // : (콜론) 빠지니까 모든 값이 하나로 묶여서 체크됨... 왜그랬을까?
  • <input type="radio" :value="tmp.value" v-model="state.radio"/>{{ tmp.value }}
                // 왜 name으로 안묶어도 되지?
profile
keep going

0개의 댓글