创建评论模块 comment 目录下创建 comment.controller.ts、comment.router.ts、comment.service.ts、comment.middleware.ts 。
comment.controller.ts:
1 import { Request, Response, NextFunction } from "express";
comment.router.ts:
1 2 3 4 5 6 7 8 9 import express from "express"; import * as commentController from "./comment.controller"; const router = express.Router(); /** * 导出路由 */ export default router;
comment.service.ts:
1 import { connection } from "../app/database/mysql";
comment.middleware.ts:
1 import { Request, Response, NextFunction } from "express";
在 app/index.ts 中引入 comment.router 并使用路由
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 import express from "express"; import postRouter from "../post/post.router"; import userRouter from "../user/user.router"; import authRouter from "../auth/auth.router"; import fileRouter from "../file/file.router"; import tagRouter from "../tag/tag.router"; import commentRouter from "../comment/comment.router"; import { defaultErrorHandler } from "./app.middleware"; /** * 创建应用 */ const app = express(); /** * 导入处理json使用的中间件 */ app.use(express.json()); /** * 路由 */ app.use( postRouter, userRouter, authRouter, fileRouter, tagRouter, commentRouter ); /** * 默认异常处理器 */ app.use(defaultErrorHandler); /** * 导出应用 */ export default app;
创建评论数据表 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 CREATE TABLE `comment`( `id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, `content` LONGTEXT, `postId` INT(11) NOT NULL, `userId` INT(11) NOT NULL, `parentId` INT(11) DEFAULT NULL, FOREIGN KEY (`postId`) REFERENCES `post`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, FOREIGN KEY (`parentId`) REFERENCES `comment`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
定义存储评论数据的功能 新建 comment.model.ts,用来描述参数类型
1 2 3 4 5 6 7 export class CommentModel { id?: number; content?: string; postId?: number; userId?: number; parentId?: number; }
comment.service.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import { connection } from "../app/database/mysql"; import { CommentModel } from "./comment.model"; /** * 创建评论 */ export const createComment = async (comment: CommentModel) => { // 准备查询 const statement = ` INSERT INTO comment SET ? `; // 执行查询 const [data] = await connection.promise().query(statement, comment); // 提供数据 return data; };
定义发表评论用的接口 comment.controller.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 import { Request, Response, NextFunction } from "express"; import { createComment } from "./comment.service"; /** * 发表评论 */ export const store = async ( request: Request, response: Response, next: NextFunction ) => { // 准备数据 const { id: userId } = request.user; const { content, postId } = request.body; const comment = { content, postId, userId, }; try { // 保存评论 const data = await createComment(comment); // 做出响应 response.status(201).send(data); } catch (error) { next(error); } };
comment.router.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import express from "express"; import { authGuard } from "../auth/auth.middleware"; import * as commentController from "./comment.controller"; const router = express.Router(); /** * 发表评论 */ router.post("/comments", authGuard, commentController.store); /** * 导出路由 */ export default router;
定义检查评论是否为回复评论的功能 comment.service.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 /** * 检查评论是否是回复评论 */ export const isReplyComment = async (commentId: number) => { // 准备查询 const statement = ` SELECT parentId FROM comment WHERE id = ? `; // 执行查询 const [data] = await connection.promise().query(statement, commentId); // 提供数据 return data[0].parentId ? true : false; };
定义回复评论接口 comment.controller.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 /** * 回复评论 */ export const reply = async ( request: Request, response: Response, next: NextFunction ) => { // 准备数据 const { commentId } = request.params; const parentId = parseInt(commentId, 10); const { id: userId } = request.user; const { content, postId } = request.body; const comment = { content, postId, userId, parentId, }; try { // 检查评论是否为回复评论 const reply = await isReplyComment(parentId); if (reply) return next(new Error("UNABLE_TO_REPLY_THIS_COMMENT")); //在app.middleware.ts中统一处理 } catch (error) { return next(error); } try { // 回复评论 const data = await createComment(comment); // 做出响应 response.status(201).send(data); } catch (error) { next(error); } };
comment.router.ts:
1 2 3 4 /** * 回复评论 */ router.post("/comments/:commentId/reply", authGuard, commentController.reply);
定义修改评论内容用的功能 comment.service.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 /** * 修改评论 */ export const updateComment = async (comment: CommentModel) => { // 准备数据 const { id, content } = comment; // 准备查询 const statement = ` UPDATE comment SET content = ? WHERE id = ? `; // 执行查询 const [data] = await connection.promise().query(statement, [content, id]); // 提供数据 return data; };
定义修改评论接口 comment.controller.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 /** * 修改评论 */ export const update = async ( request: Request, response: Response, next: NextFunction ) => { // 准备数据 const { commentId } = request.params; const { content } = request.body; const comment = { id: parseInt(commentId, 10), content, }; try { // 修改评论 const data = await updateComment(comment); // 做出响应 response.send(data); } catch (error) { next(error); } };
comment.router.ts:
1 2 3 4 5 6 7 8 9 /** * 修改评论 */ router.patch( "/comments/:commentId", authGuard, accessControl({ possession: true }), commentController.update );
定义删除评论用的功能 comment.service.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 /** * 删除评论 */ export const deleteComment = async (commentId: number) => { // 准备查询 const statement = ` DELETE FROM comment WHERE id = ? `; // 执行查询 const [data] = await connection.promise().query(statement, commentId); // 提供数据 return data; };
定义删除评论接口 comment.controller.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 /** * 删除评论 */ export const destroy = async ( request: Request, response: Response, next: NextFunction ) => { // 准备数据 const { commentId } = request.params; try { // 删除评论 const data = await deleteComment(parseInt(commentId, 10)); // 做出响应 response.send(data); } catch (error) { next(error); } };
comment.router.ts:
1 2 3 4 5 6 7 8 9 /** * 删除评论 */ router.delete( "/comments/:commentId", authGuard, accessControl({ possession: true }), commentController.destroy );