작성
·
226
0
[제로초 강좌 질문 필독 사항입니다]
질문에는 여러분에게 도움이 되는 질문과 도움이 되지 않는 질문이 있습니다.
도움이 되는 질문을 하는 방법을 알려드립니다.
https://www.youtube.com/watch?v=PUKOWrOuC0c
0. 숫자 0부터 시작한 이유는 1보다 더 중요한 것이기 때문입니다. 에러가 났을 때 해결을 하는 게 중요한 게 아닙니다. 왜 여러분은 해결을 못 하고 저는 해결을 하는지, 어디서 힌트를 얻은 것이고 어떻게 해결한 건지 그걸 알아가셔야 합니다. 그렇지 못한 질문은 무의미한 질문입니다.
1. 에러 메시지를 올리기 전에 반드시 스스로 번역을 해야 합니다. 번역기 요즘 잘 되어 있습니다. 에러 메시지가 에러 해결 단서의 90%를 차지합니다. 한글로 번역만 해도 대부분 풀립니다. 그냥 에러메시지를 올리고(심지어 안 올리는 분도 있습니다. 저는 독심술사가 아닙니다) 해결해달라고 하시면 아무런 도움이 안 됩니다.
2. 에러 메시지를 잘라서 올리지 않아야 합니다. 입문자일수록 에러메시지에서 어떤 부분이 가장 중요한 부분인지 모르실 겁니다. 그러니 통째로 올리셔야 합니다.
3. 코드도 같이 올려주세요. 다만 코드 전체를 다 올리거나, 깃헙 주소만 띡 던지지는 마세요. 여러분이 "가장" 의심스럽다고 생각하는 코드를 올려주세요.
4. 이 강좌를 바탕으로 여러분이 응용을 해보다가 막히는 부분, 여러 개의 선택지 중에서 조언이 필요한 부분, 제 경험이 궁금한 부분에 대한 질문은 대환영입니다. 다만 여러분의 회사 일은 질문하지 마세요.
5. 강좌 하나 끝날 때마다 남의 질문들을 읽어보세요. 여러분이 곧 만나게 될 에러들입니다.
6. 위에 적은 내용을 명심하지 않으시면 백날 강좌를 봐도(제 강좌가 아니더라도) 실력이 늘지 않고 그냥 코딩쇼 관람 및 한컴타자연습을 한 셈이 될 겁니다.
사진업로드를 하려할때 미리보기가 뜨지 않습니다. uploads에는 올린 사진들이 잘 뜹니다.
게시글을 업로드하려 짹짹을 누르면 post 라우터가 없다고 뜹니다.
POST /post 라우터가 없습니다.
Error: POST /post 라우터가 없습니다.
at C:\Users\jyoun\udr_node\lecture\ch9\app.js:53:18
at Layer.handle [as handle_request] (C:\Users\jyoun\udr_node\lecture\ch9\node_modules\express\lib\router\layer.js:95:5)
at trim_prefix (C:\Users\jyoun\udr_node\lecture\ch9\node_modules\express\lib\router\index.js:328:13)
at C:\Users\jyoun\udr_node\lecture\ch9\node_modules\express\lib\router\index.js:286:9
at Function.process_params (C:\Users\jyoun\udr_node\lecture\ch9\node_modules\express\lib\router\index.js:346:12)
at next (C:\Users\jyoun\udr_node\lecture\ch9\node_modules\express\lib\router\index.js:280:10)
at C:\Users\jyoun\udr_node\lecture\ch9\node_modules\express\lib\router\index.js:646:15
at next (C:\Users\jyoun\udr_node\lecture\ch9\node_modules\express\lib\router\index.js:265:14)
at C:\Users\jyoun\udr_node\lecture\ch9\routes\page.js:12:3
at Layer.handle [as handle_request] (C:\Users\jyoun\udr_node\lecture\ch9\node_modules\express\lib\router\layer.js:95:5)
controllers/post.js
const Post = require('../models/post');
const Hashtag = require('../models/hashtag');
exports.afterUploadImage = (req, res) => {
console.log(req.file);
res.json({ url: `/img/${req.file.filename}` });
};
exports.uploadPost = async (req, res, next) => {
try {
const post = await Post.create({
content: req.body.content,
img: req.body.url,
UserId: req.user.id,
});
const hashtags = req.body.content.match(/#[^\s#]*/g);
if (hashtags) {
const result = await Promise.all(hashtags.map((tag) => {
return Hashtag.findOrCreate({
where: { title: tag.slice(1).toLowerCase() }
});
}));
console.log('result', result);
await post.addHashtags(result.map(r => r[0]));
}
res.redirect('/');
} catch (error) {
console.error(error);
next(error);
}
};
routes/post.js
const express = require('express');
const multer = require('multer');
const path = require('path');
const fs = require('fs');
const { afterUploadImage, uploadPost } = require('../controllers/post');
const { isLoggedIn } = require('../middlewares');
const router = express.Router();
try {
fs.readdirSync('uploads');
} catch (error) {
console.error('uploads 폴더가 없어 uploads 폴더를 생성합니다.');
fs.mkdirSync('uploads');
}
const upload = multer({
storage: multer.diskStorage({
destination(req, file, cb) {
cb(null, '/uploads');
},
filename(req, file, cb) {
const ext = path.extname(file.originalname);
cb(null, path.basename(file.originalname, ext) + Date.now() + ext);
},
}),
limits: { fileSize: 5 * 1024 * 1024 },
});
// POST /post/img
router.post('/img', isLoggedIn, upload.single('img'), afterUploadImage);
// POST /post
const upload2 = multer();
router.post('/', isLoggedIn, upload2.none(), uploadPost);
module.exports = router;
개발자 도구로 보면 짹짹을 눌렀을때 갈곳이 없다는데 저는 깃헙 복사해서 똑같이 했는데 뭐가 문제인지 모르겠습니다.
app.js
const express = require('express');
const cookieParser = require('cookie-parser');
const morgan = require('morgan');
const path = require('path');
const session = require('express-session');
const nunjucks = require('nunjucks');
const dotenv = require('dotenv');
const passport = require('passport');
dotenv.config();
const pageRouter = require('./routes/page');
const authRouter = require('./routes/auth');
const { sequelize } = require('./models');
const passportConfig = require('./passport');
const app = express();
passportConfig(); // 패스포트 설정
app.set('port', process.env.PORT || 8001);
app.set('view engine', 'html');
nunjucks.configure('views', {
express: app,
watch: true,
});
sequelize.sync({ force: false })
.then(() => {
console.log('데이터베이스 연결 성공');
})
.catch((err) => {
console.error(err);
});
app.use(morgan('dev'));
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(session({
resave: false,
saveUninitialized: false,
secret: process.env.COOKIE_SECRET,
cookie: {
httpOnly: true,
secure: false,
},
}));
app.use(passport.initialize());
app.use(passport.session());
app.use('/', pageRouter);
app.use('/auth', authRouter);
app.use((req, res, next) => {
const error = new Error(`${req.method} ${req.url} 라우터가 없습니다.`);
error.status = 404;
next(error);
});
app.use((err, req, res, next) => {
res.locals.message = err.message;
res.locals.error = process.env.NODE_ENV !== 'production' ? err : {};
res.status(err.status || 500);
res.render('error');
});
app.listen(app.get('port'), () => {
console.log(app.get('port'), '번 포트에서 대기중');
});
main.html
{% extends 'layout.html' %}
{% block content %}
<div class="timeline">
{% if user %}
<div>
<form id="twit-form" action="/post" method="post" enctype="multipart/form-data">
<div class="input-group">
<textarea id="twit" name="content" maxlength="140"></textarea>
</div>
<div class="img-preview">
<img id="img-preview" src="" style="display: none;" width="250" alt="미리보기">
<input id="img-url" type="hidden" name="url">
</div>
<div>
<label id="img-label" for="img">사진 업로드</label>
<input id="img" type="file" accept="image/*">
<button id="twit-btn" type="submit" class="btn">짹짹</button>
</div>
</form>
</div>
{% endif %}
<div class="twits">
<form id="hashtag-form" action="/hashtag">
<input type="text" name="hashtag" placeholder="태그 검색">
<button class="btn">검색</button>
</form>
{% for twit in twits %}
<div class="twit">
<input type="hidden" value="{{twit.User.id}}" class="twit-user-id">
<input type="hidden" value="{{twit.id}}" class="twit-id">
<div class="twit-author">{{twit.User.nick}}</div>
{% if not followingIdList.includes(twit.User.id) and twit.User.id !== user.id %}
<button class="twit-follow">팔로우하기</button>
{% endif %}
<div class="twit-content">{{twit.content}}</div>
{% if twit.img %}
<div class="twit-img"><img src="{{twit.img}}" alt="섬네일"></div>
{% endif %}
</div>
{% endfor %}
</div>
</div>
{% endblock %}
{% block script %}
<script>
if (document.getElementById('img')) {
document.getElementById('img').addEventListener('change', function(e) {
const formData = new FormData();
console.log(this, this.files);
formData.append('img', this.files[0]);
axios.post('/post/img', formData)
.then((res) => {
document.getElementById('img-url').value = res.data.url;
document.getElementById('img-preview').src = res.data.url;
document.getElementById('img-preview').style.display = 'inline';
})
.catch((err) => {
console.error(err);
});
});
}
document.querySelectorAll('.twit-follow').forEach(function(tag) {
tag.addEventListener('click', function() {
const myId = document.querySelector('#my-id');
if (myId) {
const userId = tag.parentNode.querySelector('.twit-user-id').value;
if (userId !== myId.value) {
if (confirm('팔로잉하시겠습니까?')) {
axios.post(`/user/${userId}/follow`)
.then(() => {
location.reload();
})
.catch((err) => {
console.error(err);
});
}
}
}
});
});
</script>
{% endblock %}