-- DB접속하기
서버주소 : 1.234.5.158, 포트번호 : 37017, DB명 : db200
아이디: id219 , 암호: pw219
==================================================
// -- 벡엔드 만들기
CMD> express -e exp_20220126
CMD> cd exp_20220126
CMD> npm install => node_modules
CMD> nodemon --inspect ./bin/www => 실행 (소스코드 변경 적용됨)
크롬에서 localhost:3000 로 확인
==================================================
// 참고 : https://github.com/expressjs/multer
// -- 파일첨부 모듈 설치
CMD> npm install multer --save
// 참고 : https://github.com/mongodb/node-mongodb-native
CMD> npm i mongodb --save
==================================================
// 파일명 : config/mongodb.js
module.exports = {
URL : 'mongodb://id200:pw200@1.234.5.158:37017/db200',
ID : 'id200',
PW : 'pw200',
DB : 'db200',
};
==================================================
-- 한개 추가
db.sequence.insert(
{ _id : 'SEQ_BOARD1_NO', seq : 100 }
);
==================================================
파일명 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 indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var boardRouter = require('./routes/board');
var memberRouter = require('./routes/member');
var itemRouter = require('./routes/item');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
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('/index', indexRouter);
app.use('/users', usersRouter);
app.use('/board', boardRouter);
app.use('/member', memberRouter);
app.use('/item', itemRouter);
// 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;
==================================================
파일명 config/mongodb.js
필요한 정보 저장(다른 파일에서 DB에 관한 정보 전달)
module.exports ={
URL : 'mongodb://id219:pw219@1.234.5.158:37017/db219',
ID : 'id219',
PW : 'pw219',
DB : 'db219',
}
==================================================
파일명 routes/board.js
var express = require('express');
var router = express.Router();
// CMD> npm i mongodb --save
// config/mongodb.js 에서 DB내용 불러와서 연결
const db = require('mongodb').MongoClient;
const dburl = require('../config/mongodb').URL;
const dbname = require('../config/mongodb').DB;
// 이미지 파일 전송
//CMD> npm i multer --save
const multer = require('multer');
// 특정 폴더에 파일로
// 메모리 DB에 추가
const upload = multer({storage:multer.memoryStorage()});
// POST : insert
// PUT : update
// DELETE : delete
// GET : select
// localhost:3000/board/insert
// title, content, writer, image
// _id, regdate
router.post('/insert', upload.single("image"), async function(req, res, next) {
//req로 데이터가 들어옴 res로 처리 결과가 나감
try{
// 1. DB접속
const dbconn = await db.connect(dburl);
// 2. DB선택 및 컬렉션 선택
const collection = dbconn.db(dbname).collection('sequence');
// 3. 시퀀스에서 값을 가져오고, 그 다음을 위해서 가지고 올때 값 증가
const result = await collection.findOneAndUpdate(
{ _id : 'SEQ_BOARD1_NO' }, // 가저오기 위한 조건
{ $inc : {seq : 1} } // seq갑을 1 증가시킴
);
console.log('========================');
// 4. 정상동작 유무를 위한 결과 확인
console.log(result.value.seq);
console.log('========================');
const obj = {
_id : result.value.seq,
title : req.body.title,
content : req.body.content,
writer : req.body.writer,
hit : 1,
filename : req.file.originalname,
filedata : req.file.buffer,
filetype : req.file.mimetype,
filesize : req.file.size,
regdate : new Date()
};
// 추가할 컬렉션 선택
const collection1 = dbconn.db(dbname).collection('board1');
// 추가하기
const result1 = await collection1.insertOne(obj);
// 결과 확인
if(result1.insertedId === result.value.seq) {
return res.send({status : 200});
}
// console.log(result1);
// console.log(req.body);
// console.log(req.file);
return res.send({status : 0});
}
catch(e){
console.error(e);
res.send({status : -1, message:e});
}
});
// localhost:3000/board/image?_id=108
// 출력하고자 하는 이미지의 게시물 번호 전달
router.get('/image', async function(req,res,next){
try{
const no = Number(req.query['_id']);
// const no = req.query._id
// DB연결
const dbconn = await db.connect(dburl);
// DB선택 및 컬렉션 선택
const collection = dbconn.db(dbname).collection('board1');
// 이미지 정보 가져오기
const result = await collection.findOne(
{ _id : no }, //조건
{ projection : {filedata:1, filetype:1} }, // 필요한 항목만 projection
);
// console.log(result);
// application/json => image/png
res.contentType(result.filetype);
return res.send(result.filedata.buffer);
}
catch(e){
console.error(e);
res.send({status : -1, message:e});
}
});
// localhost:3000/board/select?page=1&text=검색어
// 페이지 정렬
router.get('/select', async function(req,res,next){
try{
const page = Number(req.query.page); // 페이지번호
const text = req.query.text; // 검색어
// DB연결, DB선택 및 컬렉션 선택
const dbconn = await db.connect(dburl);
const collection = dbconn.db(dbname).collection('board1');
// find(조건).sort(정렬).toArray()로 사용
// abc => a, b, c 로 검색 가능
const result = await collection.find(
{ title : new RegExp(text,'i') }, // 조건 i= 대소문자 무시
{ projection : { _id:1 , title:1, writer:1, hit:1, regdate:1 } }
)
.sort({ _id : -1 }) //-1 내림차순 +1 오름차순
.skip( (page-1)*10 ) //skip(페이지 넘기는 수)
.limit(10) //limit(10) 10개씩 정렬
.toArray();
// 오라클(o), mysql SQL문 => SELECT * FROM ORDER BY _ID DESC ...
//결과 확인
console.log(result);
// 검색어가 포함된 전체 게시물 개수 => 페이지네이션 번호 생성시 필요
const result1 = await collection.countDocuments(
{ title : new RegExp(text, 'i') },
);
return res.send({ status : 200, rows : result, total : result1 });
}
catch(e){
console.error(e);
res.send({status : -1, message:e});
}
});
module.exports = router;
==================================================
파일명 routes/item.js
var express = require('express');
var router = express.Router();
// config/mongodb.js 에서 DB내용 불러와서 연결
const db = require('mongodb').MongoClient;
const dburl = require('../config/mongodb').URL;
const dbname = require('../config/mongodb').DB;
// 이미지 파일 전송
// 메모리 DB에 추가
const multer = require('multer');
const upload = multer({storage:multer.memoryStorage()});
// 컬렉션은 itme1에 항목을 추가하는것
// localhost:3000/item/insert
// 전송되는 값 : name,content,price,quantity,image
// 자동으로 생성 : _id,regdate
router.post('/insert', upload.single("image"),async function(req, res, next) {
try{
// DB접속
const dbconn = await db.connect(dburl);
// 2. DB선택 및 컬렉션 선택
const collection = dbconn.db(dbname).collection('sequence');
// 3. 시퀀스에서 값을 가져오고, 그 다음을 위해서 가지고 올때 값 증가
const result = await collection.findOneAndUpdate(
{ _id : 'SEQ_ITEM1_NO' },
{ $inc : {seq : 1} }
);
// console.log('========================');
// console.log(result.value.seq);
// console.log('========================');
const obj = {
_id : result.value.seq,
name : req.body.name,
content : req.body.content,
price : Number(req.body.price),
quantity : Number(req.body.quantity),
filename : req.file.originalname,
filedata : req.file.buffer,
filetype : req.file.mimetype,
filesize : req.file.size,
regdate : new Date()
};
// DB선택.컬렉션 생성 및 선택
const collection1 = dbconn.db(dbname).collection('item1');
// 선택된 컬렉션에 데이터 추가
const result1 = await collection1.insertOne(obj);
if(result1.insertedId === result.value.seq) {
return res.send({status : 200});
}
// console.log('========================');
// console.log(result1);
// console.log('========================');
// console.log(req.body);
// console.log('========================');
// console.log(req.file);
// console.log('========================');
return res.send({status : 0});
}
catch(e){
console.error(e);
res.send({status : -1, message:e});
}
});
module.exports = router;
==================================================
파일명 : vue.config.js => 변경시 서버 재구동
module.exports = {
devServer : {
// 벡엔드의 주소를 짧게 사용하기 위해서
// http://localhost:3000/board/select => board/select
proxy : {
'/board' :{
target : 'http://localhost:3000',
changeOrigin : true,
logLevel : 'debug'
}
},
port : 8080
},
}
==================================================
파일명 src/component/Board.vue
<template>
<div>
<h3>src/component/Board.vue</h3>
<router-link to="/boardwrite">글쓰기</router-link>
<table border="1">
<thead>
<tr>
<th>no</th>
<th>title</th>
<th>writer</th>
<th>hit</th>
<th>date</th>
</tr>
</thead>
<tbody>
<tr v-for="tmp in state.items.result" :key="tmp">
<td @click="handleBoardContent(tmp._id)">{{tmp._id}}</td>
<td>{{ tmp.title }}</td>
<td>{{ tmp.writer }}</td>
<td>{{ tmp.hit }}</td>
<td>{{ tmp.regdate }}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import { onMounted, reactive } from 'vue';
import { useRouter } from 'vue-router';
import axios from 'axios'
export default {
setup () {
const router = useRouter();
const state = reactive({
items : {},
page : 1,
text : '',
});
// 생명주기 onMounted()
onMounted( async() => {
const url = `/board/select?page=${state.page}&text=${state.text}`
const headers = {"Content-Type":"application/sjon"};
const response = await axios.get(url,{headers});
console.log(response.data);
if(response.data.status === 200 ){
state.items.result = response.data.rows;
}
});
// function handleBoardContent(no) { }
const handleBoardContent = (no) =>{
console.log(no);
// 127.0.0.1:3000/boardcontent?no=2
router.push({name:"BoardContent", query:{no:no}});
}
return {state, handleBoardContent}
},
}
</script>
<style lang="scss" scoped>
</style>
==================================================
파일명 src/component/BoardWrite.vue
<template>
<div>
<h3>src/component/BoardWrite.vue</h3>
{{state}}<br />
제목 : <input type="text" v-model="state.title"/><br />
내용 :
<div style="width:600px">
<ckeditor :editor="editor.editor" :config="editor.editorConfig" v-model="state.content"></ckeditor>
</div>
작성자 : <input type="text" v-model="state.writer" /><br />
이미지 : <img :src="state.imgurl" style="width:50px;height:50px"/>
<input type="file" @change="handleImage"/><br />
<button @click="handleWrite">글쓰기</button>
</div>
</template>
<script>
import { reactive } from 'vue';
import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
import axios from 'axios';
import { useRouter } from 'vue-router';
export default {
setup () {
const router = useRouter();
//object
const editor ={
editor : ClassicEditor,
editorData : <p>테스트</p>,
editorConfig : {}
}
const state = reactive({
title : '',
content : '',
writer : '',
imgdata : '',
imgurl : require('../assets/default.jpg'),
});
const handleImage = (e) =>{
console.log(e);
if(e.target.files[0]){// 첨부
state.imgdata = e.target.files[0];
// 크롬 내부에 임시로 이미지를 표시하기 위한 URL생성
state.imgurl = URL.createObjectURL(e.target.files[0]);
}
else{// 취소
state.imfdata = '';
state.imgurl = require('../assets/default.jpg');
}
};
const handleWrite = async() =>{
if(state.title === ''){
alert('제목을 입력하세요.');
return false;
}
if(state.content === ''){
alert('내용을 입력하세요.');
return false;
}
if(state.writer === ''){
alert('작성자를 입력하세요.');
return false;
}
if(state.imgdata === ''){
alert('사진을 입력하세요.');
return false;
}
// 유효성 검사 후 백엔드 호출
const url = `/board/insert`;
// 이미지 파일이 있어서 application이 아닌 multipart/form-data사용
const headers = {"Content-Type":"multipart/form-data"};
const body = new FormData(); // 이미지가 있는 경우
body.append("title", state.title);
body.append("content", state.content);
body.append("writer", state.writer);
body.append("image", state.imgdata);
const response = await axios.post(url,body,{headers});
console.log(response.data);
if(response.data.status === 200){
alert('작성이 완료 되었습니다.');
router.push({name:"Board"});
}
};
return {state, handleImage, handleWrite, editor}
}
}
</script>
<style lang="css">
.ck-editor__editable {
min-height: 500px;
}
</style>
==================================================
파일명 src/components/boardcontent.vue
<template>
<div>
<h3>src/components/boardcontent.vue</h3>
{{state}}
<img :src="`/board/image?_id=${state.no}`" style="width:100px; height:100px"/>
</div>
</template>
<script>
import { reactive } from 'vue';
import { onMounted } from 'vue';
import { useRoute } from 'vue-router';// query 받기
export default {
setup () {
const route = useRoute();
const state = reactive({
no : route.query.no
});
onMounted( async() => {
//const url = `/board/selectone`;
});
return {state}
}
}
</script>
<style lang="scss" scoped>
</style>