글목록 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=113
글1개조회 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으로 안묶어도 되지?