谈谈MVC模式
www.ruanyifeng.com/blog/2007/1…
MVC是模型(Model)、视图(View)和控制器(Controller)的缩写。这一软件架构模式诞生于20世纪70年代后期,被用于创建桌面应用。当然现在这一模式也在web应用中被广泛使用。
什么是mvc,为什么使用它?
在计算机科学中,MVC是一种软件设计模式,这种模式将应用代码组织成三个相互交织的部分——模型、视图和控制器。
MVC 是三个单词的首字母缩写,它们是Model(模型)、View(视图)和 Controller (控制)。
模型是与数据库交互的逻辑;视图是用户接口和交互,控制器是是视图和数据库之间的中介。
大多数情况下,视图不直接和模型交互——这个功能由控制器执行。
在其他一些框架中,模型与视图直接交互。
MVC 设计模式旨在将应用代码分成各自的单位,来简化维护和优化。这种方式被称为“ 关注点分离 ”。
用Windows的计算器小程序为例,解释一下 MVC 模式
Mvc的模型是什么?
需要运算的数字就是"模型",
Mvc的视图是什么?
计算器上的那些按钮和最上面的显示条,就是"视图",
视图负责直接和用户交互,视图与控制器沟通用户通过鼠标或者键盘发出的请求,将信息显示给用户(可以定义多个视图)。
Mvc的控制器是什么?
执行加减乘除的那些内部运算步骤就是"控制器"。
处理用户输入的信息。负责从视图读取数据,控制用户输入,并向模型发送数据,是应用程序中处理用户交互的部分。负责管理与用户交互交互控制。
类比
- 你打电话给餐厅点了一份披萨 – 你是
view - 你向服务员点单 – 服务员是
controller - 服务员从披萨店拿到披萨并送给你 – 披萨店是
model
需求分析
在Web系统中,用户登录是最基本的功能。要实现用户名+密码登录,很多同学的第一想法就是直接创建一个Users集合,包含username和password两个字段,这样,就可以实现登录了:
好了,回到正题,我们从下面逻辑当中可以抽离出如下字段:username和password和email
模块拆分解耦
开始编码
安装相关依赖
jsonwebtoken 用于生成token
bcrypt 用于加密用户提交的信息
pnpm add bcrypt
pnpm add @types/bcrypt -D
pnpm add jsonwebtoken
pnpm add @types/jsonwebtoken -D
- 定义Model,表示数据库保存用户登陆注册的字段类型:
user.model.ts
import { model, Schema } from "mongoose"//对象的解构赋值
import { IUser } from "./user.interface"
// 定义和约束文档字段的类型
const userScema = new Schema<IUser>({
name:{
type:String,
required:true,
trim: true,
},
//此处额外定义该字段是为了用来验证用户是否已注册过
email:{
type:String,
required:true,
trim: true,
},
password:{
type:String,
required:true,
trim: true,
},
})
export const User = model("User", userScema)
- 定义相关字段的TS类型声明
user.interface.ts
export interface IUser {
name:string;
email:string;
password:string;
}
- 定义路由,负责响应用户的请求
user.route.ts
//路由进行模块化,更好的管理路由
import express from "express";
import {
createUser,
loginUser,
} from "./user.controller";
const UserRouter = express.Router();
UserRouter.post("/register", createUser);
UserRouter.post("/login", loginUser);
export default UserRouter;
app.ts
import express, { Application } from "express"; import UserRouter from "./app/modules/user/user.route"; const app: Application = express(); // 解析请求体的内容 app.use(express.json()); app.use(express.urlencoded({ extended: true })); // 挂载路由 app.use("/user", UserRouter); export default app;
- 定义controller,负责通知model进行数据更新
user.controller.ts
import { Request, Response } from "express";
import bcrypt from "bcrypt";
import { User } from "./user.model";
require("dotenv").config();
export const createUser = async (req: Request, res: Response) => {
try {
const userinfo = req.body;
const { name,email, password } =
userinfo;
const enryptedpass = await bcrypt.hash(password, 10);
const alreayExist = await User.findOne({ email: email });
if (alreayExist) {
res.send({ message: "User Is Alreay Exist" });
} else {
const user = new User({
name,
email,
password,
});
await user.save();
res.status(200).send({ message: "success" });
}
} catch (e) {
res.send({ message: "custome error" });
}
};
export const loginUser = async (req: Request, res: Response) => {
try {
const userinfo = req.body;
const { email, password } = userinfo;
const validuser = await User.findOne({ email: email });
if (validuser) {
const validPass = await bcrypt.compare(password, validuser.password);
if (validPass) {
const token = jwt.sign(
{ email: validuser.email },
`${process.env.JWT_SECRET}`,
{ expiresIn: "1d" }
);
res.status(200).send({ message: "Login Successful", data: token });
} else {
res.send({ message: "password not Match" });
}
} else {
res.send({ message: "user not Valid" });
}
} catch (e) {
res.send({ message: "custom error" });
}
};
- 调用接口进行登陆
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<form action="http://localhost:5001/user/login" method="POST">
email<input type="text" name="email">
password<input type="password" name="password">
<button type="submit">提交</button>
</form>
</div>
</body>
</html>
可以看到已登陆成功并收到来自服务器的响应
- 注册
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<form action="http://localhost:5001/user/register" method="POST">
name<input type="text" name="name">
email<input type="text" name="email">
password<input type="password" name="password">
<button type="submit">提交</button>
</form>
</div>
</body>
</html>