NEXTJSを使用してTwitterをクローンする(multerを使用して画像をアップロードする)
バックエンド
multer
Multierはファイルをアップロードするための multipart/form-data
処理に使用するノード.jsのミドルウェアです.効率を最大限に高める. busboy に基づいて
設定
npm i multer
使用方法
storage
ディスクストレージエンジンは、ファイルをディスクに保存するすべての制御機能を提供します.limits
ファイルサイズの制限に使用します.const multer = require("multer");
const path = require("path");
const upload = multer({
storage: multer.diskStorage({
destination(req, file, done) {
done(null, "uploads");
},
filename(req, file, done) {
// file.originalname 파일 이름 (이재훈.png)
const ext = path.extname(file.originalname); //확장자 추출(.png)
const basename = path.basename(file.originalname); // 이름 추출 (이재훈)
done(null, basename + new Date().getTime() + ext); // (이재훈213123123.png)
},
}),
limits: { fieldSize: 20 * 1024 * 1024 }, // 20MB
});
destination
第二課 filename
の各見出しページがあります.どちらのオプションも、ファイルがどこに保存されるかを指定する関数です.destination
オプション:アップロードしたファイルを保存するフォルダを指定します.これは. string
形状で与えることができます(はい. '/tmp/uploads'
). もしも destination
オプションが指定されていない場合、オペレーティングシステムは一時ファイルを格納するデフォルトディレクトリを使用します.filename
フォルダに格納されているファイル名を決定します.もしも filename
ない場合は、各ファイルにランダムな名前が付けられますが、ファイル拡張子は除外されます.router.post("/images", isLoggedIn, upload.array("image"), postImages);
req.filesにはimage
というファイル情報が含まれています.exports.postImages = (req, res, next) => {
return res.json(req.files.map(v => v.filename));
};
ファイル名をフロントに送信します.
画像をUploadsフォルダに入れたので、フロントからファイルにアクセスできるようにする必要があります.app.use("/", express.static(path.join(__dirname, "uploads")));
Upload Post
.none()
テキストフィールドのみを許可します.ファイルがアップロードされている場合、「LIMIT UNEXPECTED FILE」などのエラーコードが表示されます.これは. upload.fields([])
同じ操作を行います.router.post("/", isLoggedIn, upload.none(), createPost);
exports.createPost = async (req, res, next) => {
try {
const { content, image } = req.body;
const { id: UserId } = req.user;
const post = await Post.create({
content,
UserId,
});
if (image) {
if (Array.isArray(image)) {
// 이미지를 여러개 올리면 image: ["이.png", "재.png"]
const dbImages = await Promise.all(
image.map(imagePath => Image.create({ src: imagePath }))
);
await post.addImages(dbImages);
} else {
// 이미지를 하나만 올리면 image: "이.png"
const dbImage = await Image.create({ src: image });
await post.addImages(dbImage);
}
}
...
フロントからPostのコンテンツと画像パスを受信し、Postを作成します.
画像があれば、画像が並べられている場合はPromise.allは画像を作成し、addImagesはpostと画像を接続します.
HashTag
さらに、ユーザがコンテンツに#などのハッシュタグを追加する場合、ハッシュタグも作成する必要がある.exports.createPost = async (req, res, next) => {
try {
const { content, image } = req.body;
const { id: UserId } = req.user;
const hashtags = content.match(/#[^\s#]+/g);
const post = await Post.create({
content,
UserId,
});
if (hashtags) {
const result = await Promise.all(
hashtags.map(hashtag =>
Hashtag.findOrCreate({
where: { name: hashtag.slice(1).toLowerCase() },
})
)
); // [[노드,true],[리액트,true]]
await post.addHashtags(result.map(v => v[0]));
}
...
まずhashtagsが存在するかどうかを検索します.matchメソッドのパラメータを使用して正規表現を記述する場合は、対応する正規表現としてのみ列挙されます.
findOrCreateメソッドを使用して、配列に作成されたhashtagsをdbに保存します.findOrCreate
クエリー・オプションを満たすアイテムが見つからない場合、findOrCreateメソッドはテーブルにアイテムを作成します.
戻り値は配列첫번째 인덱스
であり、인스턴스를
はインスタンスが存在するかどうかを示す.
最後に、addHashtagメソッドを使用してpostとhashtagを接続します.
フロントエンド
FormData
두번째 인덱스
はFormDataオブジェクトで、Ajaxを使用してフォームを転送できます.
ページ切り替えなしにフォームデータを送信する場合は、すぐにFormDataオブジェクトを使用します.
append()メソッドを使用してキー値を追加します.
作成されたBoolean
FromData
.const PostForm = () => {
//...
const onChangeImages = useCallback(e => {
console.log("images", e.target.files);
const imageFormData = new FormData();
[].forEach.call(e.target.files, f => {
imageFormData.append("image", f);
});
dispatch({
type: UPLOAD_IMAGES_REQUEST,
data: imageFormData,
});
});
return (
<Form
style={{ margin: "10px 0 20px" }}
encType="multipart/form-data"
onFinish={onSubmitBtn}
>
{/* ... */
<div>
<input
type="file"
name="image"
multiple
hidden
ref={imageInput}
onChange={onChangeImages}
/>
{/* ... */
</Form>
);
};
export default PostForm;
FromData
を介してdispatch
のバックエンドに送信され、バックエンドで受信したファイル名がsaga
に再送信されるfunction uploadImagesAPI(data) {
return axios.post(`/post/images`, data);
}
function* uploadImages(action) {
try {
const result = yield call(uploadImagesAPI, action.data);
yield put({
type: UPLOAD_IMAGES_SUCCESS,
data: result.data,
});
} catch (err) {
console.error(err);
yield put({
type: UPLOAD_IMAGES_FAILURE,
error: err.response.data,
});
}
}
受信したファイル名をformData
に入れます.case UPLOAD_IMAGES_SUCCESS: {
draft.imagePaths = action.data;
draft.uploadImagesLoading = false;
draft.uploadImagesDone = true;
break;
}
Upload Post
現在のtextが空の場合、警告ウィンドウが表示されます.dispatch
は、現在の国のstate
FormData
であり、imagePaths
でもある.
このようにして完成したappend
をaction dataに入れ、content
を生成する.const onSubmitBtn = useCallback(() => {
if (!text || !text.trim()) {
return alert("게시글을 작성하세요.");
}
const formData = new FormData();
imagePaths.forEach(image => {
formData.append("image", image);
});
formData.append("content", text);
dispatch({
type: ADD_POST_REQUEST,
data: formData,
});
}, [text, imagePaths]);
Reference
この問題について(NEXTJSを使用してTwitterをクローンする(multerを使用して画像をアップロードする)), 我々は、より多くの情報をここで見つけました
https://velog.io/@abc5259/NEXTJS-로-twitter클론-해보기multer이용해서-이미지-업로드-하기
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
npm i multer
const multer = require("multer");
const path = require("path");
const upload = multer({
storage: multer.diskStorage({
destination(req, file, done) {
done(null, "uploads");
},
filename(req, file, done) {
// file.originalname 파일 이름 (이재훈.png)
const ext = path.extname(file.originalname); //확장자 추출(.png)
const basename = path.basename(file.originalname); // 이름 추출 (이재훈)
done(null, basename + new Date().getTime() + ext); // (이재훈213123123.png)
},
}),
limits: { fieldSize: 20 * 1024 * 1024 }, // 20MB
});
router.post("/images", isLoggedIn, upload.array("image"), postImages);
exports.postImages = (req, res, next) => {
return res.json(req.files.map(v => v.filename));
};
app.use("/", express.static(path.join(__dirname, "uploads")));
router.post("/", isLoggedIn, upload.none(), createPost);
exports.createPost = async (req, res, next) => {
try {
const { content, image } = req.body;
const { id: UserId } = req.user;
const post = await Post.create({
content,
UserId,
});
if (image) {
if (Array.isArray(image)) {
// 이미지를 여러개 올리면 image: ["이.png", "재.png"]
const dbImages = await Promise.all(
image.map(imagePath => Image.create({ src: imagePath }))
);
await post.addImages(dbImages);
} else {
// 이미지를 하나만 올리면 image: "이.png"
const dbImage = await Image.create({ src: image });
await post.addImages(dbImage);
}
}
...
exports.createPost = async (req, res, next) => {
try {
const { content, image } = req.body;
const { id: UserId } = req.user;
const hashtags = content.match(/#[^\s#]+/g);
const post = await Post.create({
content,
UserId,
});
if (hashtags) {
const result = await Promise.all(
hashtags.map(hashtag =>
Hashtag.findOrCreate({
where: { name: hashtag.slice(1).toLowerCase() },
})
)
); // [[노드,true],[리액트,true]]
await post.addHashtags(result.map(v => v[0]));
}
...
FormData
두번째 인덱스
はFormDataオブジェクトで、Ajaxを使用してフォームを転送できます.ページ切り替えなしにフォームデータを送信する場合は、すぐにFormDataオブジェクトを使用します.
append()メソッドを使用してキー値を追加します.
作成された
Boolean
FromData
.const PostForm = () => {
//...
const onChangeImages = useCallback(e => {
console.log("images", e.target.files);
const imageFormData = new FormData();
[].forEach.call(e.target.files, f => {
imageFormData.append("image", f);
});
dispatch({
type: UPLOAD_IMAGES_REQUEST,
data: imageFormData,
});
});
return (
<Form
style={{ margin: "10px 0 20px" }}
encType="multipart/form-data"
onFinish={onSubmitBtn}
>
{/* ... */
<div>
<input
type="file"
name="image"
multiple
hidden
ref={imageInput}
onChange={onChangeImages}
/>
{/* ... */
</Form>
);
};
export default PostForm;
FromData
を介してdispatch
のバックエンドに送信され、バックエンドで受信したファイル名がsaga
に再送信されるfunction uploadImagesAPI(data) {
return axios.post(`/post/images`, data);
}
function* uploadImages(action) {
try {
const result = yield call(uploadImagesAPI, action.data);
yield put({
type: UPLOAD_IMAGES_SUCCESS,
data: result.data,
});
} catch (err) {
console.error(err);
yield put({
type: UPLOAD_IMAGES_FAILURE,
error: err.response.data,
});
}
}
受信したファイル名をformData
に入れます.case UPLOAD_IMAGES_SUCCESS: {
draft.imagePaths = action.data;
draft.uploadImagesLoading = false;
draft.uploadImagesDone = true;
break;
}
Upload Post
現在のtextが空の場合、警告ウィンドウが表示されます.
dispatch
は、現在の国のstate
FormData
であり、imagePaths
でもある.このようにして完成した
append
をaction dataに入れ、content
を生成する.const onSubmitBtn = useCallback(() => {
if (!text || !text.trim()) {
return alert("게시글을 작성하세요.");
}
const formData = new FormData();
imagePaths.forEach(image => {
formData.append("image", image);
});
formData.append("content", text);
dispatch({
type: ADD_POST_REQUEST,
data: formData,
});
}, [text, imagePaths]);
Reference
この問題について(NEXTJSを使用してTwitterをクローンする(multerを使用して画像をアップロードする)), 我々は、より多くの情報をここで見つけました https://velog.io/@abc5259/NEXTJS-로-twitter클론-해보기multer이용해서-이미지-업로드-하기テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol