创建标签模块 tag 目录下 tag.controller.ts、tag.middleware.ts、tag.router.ts、tag.service.ts。然后在 index.ts 中导入并使用路由。
tag.controller.ts:
1 import { Request, Response, NextFunction } from "express";
tag.middleware.ts:
1 import { Request, Response, NextFunction } from "express";
tag.router.ts:
1 2 3 4 5 6 7 8 9 import express from "express"; import * as tagController from "./tag.controller"; const router = express.Router(); /** * 导出路由 */ export default router;
tag.service.ts:
1 import { connection } from "../app/database/mysql";
创建标签数据表 1 2 3 4 5 ALTER TABLE `tag` ( `id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, `name` VARCHAR(255) NOT NULL UNIQUE KEY ) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
定义存储标签数据的功能 新建 tag.model.ts,在这个文件里可以定义去导出一个类,用它去描述一下标签这种数据。
1 2 3 4 export class TagModel { id?:number; name?:string; }
tag.service.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import { connection } from "../app/database/mysql"; import { TagModel } from "./tag.model"; /** * 创建标签 */ export const createTag = async (tag: TagModel) => { // 准备查询 const statement = ` INSERT INTO tag SET ? `; // 执行查询 const [data] = await connection.promise().query(statement, tag); // 提供数据 return data as any; };
定义按名字查找标签的功能 tag.service.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 /** * 按名字查找标签 */ export const getTagByName = async (tagName: string) => { // 准备查询 const statement = ` SELECT id, name FROM tag WHERE name = ? `; // 执行查询 const [data] = await connection.promise().query(statement, tagName); // 提供数据 return data[0]; };
定义创建标签用的接口 tag.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 import { Request, Response, NextFunction } from "express"; import { createTag, getTagByName } from "./tag.service"; /** * 创建标签 */ export const store = async ( request: Request, response: Response, next: NextFunction ) => { // 准备数据 const { name } = request.body; try { // 查找标签 const tag = await getTagByName(name); // 如果标签存在就报错 if (tag) throw new Error("TAG_ALREADY_EXISTS"); // 存储标签 const data = await createTag({ name }); // 做出响应 response.status(201).send(data); } catch (error) { next(error); //在app.middleware.ts文件中统一处理报错 } };
tag.router.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import express from "express"; import * as tagController from "./tag.controller"; import { authGuard } from "../auth/auth.middleware"; const router = express.Router(); /** * 创建标签 */ router.post("/tags", authGuard, tagController.store); /** * 导出路由 */ export default router;
内容标签:创建保存内容与标签关系用的数据表 1 2 3 4 5 6 7 8 9 10 CREATE TABLE `post_tag`( `postId` INT(11) NOT NULL, `tagId` INT(11) NOT NULL, PRIMARY KEY(`postId`,`tagId`), FOREIGN KEY(`postId`) REFERENCES `post`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, FOREIGN KEY(`tagId`) REFERENCES `tag`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
定义保存内容标签服务 给内容打上标签就是在 post_tag 数据表中创建一条数据记录,记录一下内容的 id,还有给这个内容贴上标签的 id。
post.service.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 /** * 保存内容标签 */ export const createPostTag = async (postId: number, tagId: number) => { // 准备查询 const statement = ` INSERT INTO post_tag (postId,tagId) VALUES(?,?) `; // 执行查询 const [data] = await connection.promise().query(statement, [postId, tagId]); //提供数据 return data; };
定义检查内容标签服务 post.service.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 /** * 检查内容标签 */ export const postHasTag = async (postId: number, tagId: number) => { // 准备查询 const statement = ` SELECT * FROM post_tag WHERE postId=? AND tagId=? `; // 执行查询 const [data] = await connection.promise().query(statement, [postId, tagId]); // 提供数据 return data[0] ? true : false; };
定义添加内容标签接口 post.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 39 40 41 42 43 44 45 46 47 48 /** * 添加内容标签 */ export const storePostTag = async ( request: Request, response: Response, next: NextFunction ) => { // 准备数据 const { postId } = request.params; const { name } = request.body; let tag: TagModel; // 查找标签 try { tag = await getTagByName(name); } catch (error) { return next(error); } // 找到标签,验证内容标签 if (tag) { try { const postTag = await postHasTag(parseInt(postId, 10), tag.id); if (postTag) return next(new Error("POST_ALREADY_HAS_THIS_TAG")); //在app.middleware.ts中统一处理报错 } catch (error) { return next(error); } } // 没找到标签,创建这个标签 if (!tag) { try { const data = await createTag({ name }); tag = { id: data.insertId }; } catch (error) { return next(error); } } // 给内容打上标签 try { await createPostTag(parseInt(postId, 10), tag.id); response.sendStatus(201); } catch (error) { return next(error); } };
post.router.ts:
1 2 3 4 5 6 7 8 9 /** * 添加内容标签 */ router.post( "/posts/:postId/tag", authGuard, accessControl({ possession: true }), postController.storePostTag );
定义删除内容标签服务 post.service.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 /** * 删除内容标签 */ export const deletePostTag = async (postId: number, tagId: number) => { // 准备查询 const statement = ` DELETE FROM post_tag WHERE postId = ? AND tagId = ? `; // 执行查询 const [data] = await connection.promise().query(statement, [postId, tagId]); // 提供数据 return data; };