모든 일은 가능하다고 생각하는 사람만이 해낼 수 있다.
- 정주영 -
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.2.1.min.js"
integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossorigin="anonymous"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" href="{{ url_for('static', filename='css/hh99_miniprj_easy.css') }}" />
<title>항해99 - 미니프로젝트</title>
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100;300;400;500;700;900&display=swap" rel="stylesheet">
<script>
function post() {
let title = $('#title').val();
let comment = $('#comment').val();
let author = $('#author').val();
$.ajax({
type: "POST",
url: "/hh99/board/post",
data: {title, comment, author},
success: function (response) {
alert(response.no);
window.location.href='/'
}
});
}
</script>
<style>
.wrap {
width: 500px;
margin: 200px auto;
}
</style>
</head>
<body>
<div class="wrap">
<div class="form-group">
<input type="text" class="form-control" id="title" placeholder="제목을 입력하세요">
</div>
<div class="form-group">
<input type="text" class="form-control" id="author" placeholder="글쓴이를 입력하세요">
</div>
<div class="form-group">
<textarea class="form-control" placeholder="내용을 입력하세요" id="comment" rows="5"></textarea>
</div>
<button onclick="post()" type="submit" id="btn-submit" class="btn btn-primary">글쓰기</button>
</div>
</body>
</html>
const express = require('express')
const mongoose = require('mongoose')
const app = express()
const ejs = require('ejs')
const Article = require('./models/article')
const { find } = require('./models/article')
mongoose.connect('mongodb://test:test@localhost:27017/admin', {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
})
app.set('view engine', 'ejs')
app.use(express.urlencoded({ extended: false }))
app.use(express.json())
app.get('/', async (req, res) => {
console.log('전체 리스트 보기')
res.render('./main')
})
// app.get('/hh99/board/list', async (req, res) => {
// // const articles = await Article.find().sort('-createdAt')
// // console.log(articles)
// // res.render('./main', { articles: articles })
// const articles = await Article.find({}).sort()
// console.log(articles)
// res.json({ articles: articles })
// })
app.get('/hh99/board/list', async (req, res) => {
const articles = await Article.find({}).sort()
res.json({ articles: articles })
})
// app.get('/hh99/board/list', async (req, res) => {
// const articles = await Article.find().sort()
// res.render('./main', { articles: articles })
// })
app.get('/hh99/board/post', async (req, res) => {
console.log('글쓰기 페이지')
res.render('./post')
})
app.post('/hh99/board/post', async (req, res) => {
console.log(req.body)
const article = new Article({
title: req.body.title,
comment: req.body.comment,
author: req.body.author,
})
await article.save()
res.send(article)
})
app.get('/hh99/board/view?objid=${objid}', (req, res) => {
console.log('detail 보기')
res.render('./view')
})
// app.get('/hh99/board/view/<objid>', (req, res) => {
// console.log('한 개의 포스팅에 대한 정보 보기')
// res.render('/hh99_miniprj_easy_post', {})
// })
app.listen(5000, function () {
console.log('실행중...')
})
순서대로 main.ejs파일, server.js파일이다.
아래는 해당 부분의 타겟부분만 가져와봤다.
$.ajax({
type: "GET",
url: "/hh99/board/list",
data: {},
success: function (response) {
console.log(response)
let articles = response['articles'];
app.get('/hh99/board/list', async (req, res) => {
const articles = await Article.find({}).sort()
res.send({ articles: articles })
// res.json({ articles: articles })
})
res.send와 res.json의 차이가 궁금해졌다.
위 ejs파일과, server.js와 ajax를 이용해 요청을 주고 받는 과정에서 신기한 것을 발견했다.
render는 ejs 파일 내부에 템플릿 엔진으로 사용할 수 있는 값을 보내주는 것 같다. 맨 처음 이걸 사용했다가 console.log로 response를 찍는데 그냥 해당 ejs파일 전체가 console에 찍혀서 깜짝놀랐다. 그냥 ejs 내부 어디든지
<%= articles %>와 같은 템플릿 엔진으로서만 사용이 가능한듯하다.
정말 차이점을 모르겠는 것은 send, json 요 두 가지다. send가 더 큰 개념인 것 같은데 send를 json형태로 보낸다면 둘의 차이가 없는건지 궁금하다.
성공했을 때 함수 내부로 전달하는 값인데 둘의 차이점을 모르겠다. 일단 전달되는 articles에 해당하는 부분은 같은데 추측하기로는 나머지 부분에서 전달되는 부분이 조금 차이가 있지 않을까 생각하고 있다. 나중에 쉬는 시간이나 집중 안될 때 궁금하면 자세히 보면 궁금증이 풀릴 것 같다.
처음 게시판을 만들 때는 render를 이용해서 값을 ejs로 넘기고 ejs내부 html 부분에 템플릿 엔진을 적용하여 for문으로 게시글 목록을 생성했는데 이번에 하는 방식은 render가 아니라 send를 이용하여 server.js부분의 코드도 짧아지고, ejs부분도 짧고 사용하기 쉬워진 느낌이 든다. 잘하시는 분이 추천해주신 방법인데 정말 감사하다는 생각이 든다. 파일에 내용이 얼마든지 추가되도 헷갈리지 않고 요청을 주고받을 수 있을 것 같은 느낌이든다.
전에 하던 게시판은 조이를 이용해 로그인 회원가입 규칙도 추가했다. 조이 사용법은 상당히 심플했다. npm을 이용해 joi를 인스톨하고, require을 이용해 불러오고, 스키마를 생성하여 validate해주면 완성됐다. 이제는 테스트코드 작성만 남았는데 우선 항해에서 내준 과제 먼저 끝내고 테스트코드를 작성할 예정이다.
https://github.com/awrde/node.js_my_blog
awrde/node.js_my_blog
Create my own blog without login function. Contribute to awrde/node.js_my_blog development by creating an account on GitHub.
github.com
- 회원 가입 페이지
- [x] 회원가입 버튼을 클릭하기
- [x] 닉네임, 비밀번호, 비밀번호 확인을 입력하기
- [x] 닉네임은 최소 3자 이상, 알파벳 대소문자(a~z, A~Z), 숫자(0~9)로 구성하기
- [x] 비밀번호는 최소 4자 이상이며, 닉네임과 같은 값이 포함된 경우 회원가입에 실패로 만들기
- [x] 비밀번호 확인은 비밀번호와 정확하게 일치하기
- [x] 데이터베이스에 존재하는 닉네임을 입력한 채 회원가입 버튼을 누른 경우 "중복된 닉네임입니다." 라는 에러메세지를 프론트엔드에서 보여주기
- [x] 회원가입 버튼을 누르고 에러메세지가 발생하지 않는다면 로그인 페이지로 이동시키기
- 로그인 페이지
- [x] 로그인, 회원가입 버튼을 만들기
- [x] 닉네임, 비밀번호 입력란 만들기
- [x] 로그인 버튼을 누른 경우 닉네임과 비밀번호가 데이터베이스에 등록됐는지 확인한 뒤, 하나라도 맞지 않는 정보가 있다면 "닉네임 또는 패스워드를 확인해주세요"라는 메세지를 프론트엔드에서 보여주기
- [x] 로그인 버튼을 눌러서 에러 메세지가 발생하지 않는다면 전체 게시글 목록 조회 페이지로 이동시키기
- 로그인 검사
- 아래 페이지를 제외하고 모두 로그인 한 경우만 볼 수 있도록 하기
- [x] 회원가입 페이지
- [x] 로그인 페이지
- [x] 게시글 목록 조회 페이지
- [x] 게시글 조회 페이지
- [x] 로그인을 하지 않거나 올바르지 않은 경로로 접속한 사용자가 로그인이 필요한 경로에 접속한 경우 "로그인이 필요합니다." 라는 메세지를 프론트엔드에서 띄워주고 로그인 페이지로 이동시키기
- [x] 로그인 한 사용자가 로그인 페이지 또는 회원가입 페이지에 접속한 경우 "이미 로그인이 되어있습니다."라는 메세지를 띄우고 전체 게시글 목록 조회 페이지로 이동시키기 @
- 아래 페이지를 제외하고 모두 로그인 한 경우만 볼 수 있도록 하기
- 게시글 조회 페이지 > 댓글 목록 조회
- [x] 로그인 하지 않은 사용자도 댓글 목록 조회가 가능하도록 하기
- [x] 현재 조회중인 게시글에 작성된 모든 댓글을 목록 형식으로 볼 수 있도록 하기
- [x] 댓글 목록 위에 댓글 작성란 만들기
- 댓글 작성에 관한 기능은 5번 요구사항으로 연결하기
- [x] 댓글 목록 중, 내가 작성한 댓글인 경우 댓글 수정, 댓글 삭제 버튼 만들기
- 댓글 수정 버튼을 누르면 6번 요구사항으로 연결하기
- 댓글 삭제 버튼을 누르면 7번 요구사항으로 연결하기 @ @ @
- [x] 제일 최근 작성된 댓글을 맨 위에 띄우기
- 게시글 조회 페이지 > 댓글 작성
- [x] 로그인 한 사용자만 댓글 작성이 가능하도록 하기
- [x] 게시글 조회 페이지 하단에 댓글 내용을 입력할 수 있는 댓글 작성 버튼 만들기
- [x] 로그인 하지 않은 사용자가 댓글 작성란을 누르면 "로그인이 필요한 기능입니다." 라는 메세지를 띄우고 로그인 페이지로 이동시키기
- [x] 댓글 내용란을 비워둔 채 댓글 작성 버튼을 누르면 "댓글 내용을 입력해주세요" 라는 메세지를 띄우기
- [x] 댓글 내용을 입력하고 댓글 작성 버튼을 누른 경우 작성한 댓글을 추가하기
- 게시글 조회 페이지 > 댓글 수정
- [x] 내가 작성한 댓글만 수정 가능하도록 하기
- [x] 댓글 본문이 사라지고, 댓글 내용, 저장 버튼 생성하기
- [x] 댓글 내용에는 이전에 입력했던 댓글 내용을 기본 값으로 채우기
- [x] 수정할 댓글 내용은 비어 있지 않도록 하기
- [x] 저장 버튼을 누른 경우 기존 댓글의 내용을 새로 입력한 댓글 내용으로 바꾸기
- 게시글 조회 페이지 > 댓글 삭제
- [x] 내가 작성한 댓글만 삭제 가능하도록 하기
- [x] "정말로 삭제하시겠습니까?" 메세지를 띄우고, 확인/취소 버튼 중 "확인" 버튼을 누른 경우 목록에서 해당 댓글을 삭제하기
- [x] 취소를 누른 경우 삭제되지 않고 그대로 유지하기
- 회원가입 테스트 코드 작성
- 회원가입시 구현한 아래 조건을 검사하는 테스트 코드를 작성하기
- [ ] 닉네임은 최소 3자 이상, 알파벳 대소문자(a~z, A~Z), 숫자(0~9)로 이루어져 있어야 합니다.
- [ ] 비밀번호는 최소 4자 이상이며, 닉네임과 같은 값이 포함된 경우 회원가입에 실패합니다.
- [ ] 비밀번호 확인은 비밀번호와 정확하게 일치해야 합니다.
- [ ] 데이터베이스에 존재하는 닉네임을 입력한 채 회원가입 버튼을 누른 경우 "중복된 닉네임입니다." 라는 에러메세지가 발생합니다.
- [ ] 테스트 코드 실행 시 실제로는 데이터베이스에 연결되지 않도록 하기
- [ ] 각 조건 별로 2개 이상의 테스트 케이스가 존재하도록 하기
- 회원가입시 구현한 아래 조건을 검사하는 테스트 코드를 작성하기
'TIL' 카테고리의 다른 글
20210714 [항해 38일 차] 건강 조심하자 (0) | 2021.07.14 |
---|---|
20210713 [항해 37일 차] (0) | 2021.07.13 |
20210711 [항해 35일 차] (0) | 2021.07.12 |
20210710 [항해 34일 차] (0) | 2021.07.11 |
20210709 [항해 33일 차] (0) | 2021.07.10 |