express 从0-1如何创建一个项目 注册接口

news2024/11/18 10:47:38

内容参考:
windos下安装mysql
express 使用mysql

一、创建一个空项目

在这里插入图片描述

二、创建一个包管理工具

npm init -y

在这里插入图片描述

三、安装需要的插件及app.js的部分实现

npm i express   安装express 框架
npm i cors   安装cors 用于跨域
npm install mysql2 安装mysql数据库
npm i bcryptjs 用于加密密码 。加密之后的密码,无法被逆向破解。同一明文密码多次加密,得到的加密结果各不相同,保证了安全性
npm i  @escook/express-joi 自动对表单数据进行验证
npm install joi  用于表单数据验证 解决if else 效率低下问题

创建app.js 及其代码

在这里插入图片描述

// 引入 express 框架
const express = require("express");
const cors = require("cors");
const app = express();

// 将cors 注册成全局中间件 用于跨域
app.use(cors());

// 没有配置json 返回的时undefined   没有配置urlencoded 返回的时{}
// 配置解析application/x-www-form-urlencoded(表单数据)的中间件 
app.use(express.urlencoded({ extends: false }));

// 配置json数据的中间件
app.use(express.json());

const port = 3000;

app.get("/", (req, res) => res.send("Hello World!"));
app.listen(port, () => console.log(`Example app listening on port ${port}!`));

四、创建路由模块

1、创建文件

1.在项目根目录中,新建 router 文件夹,用来存放所有的 路由 模块
路由模块中,只存放客户端的请求与处理函数之间的映射关系
2.在项目根目录中,新建 router_handler 文件夹,用来存放所有的 路由处理函数模块
路由处理函数模块中,专门负责存放每个路由对应的处理函数
3.在项目根目录中,新建 db文件夹,用于链接数据库

在这里插入图片描述

2、连接数据库 db/index.js

const mysql = require("mysql2");

// 2、建立与mysql 数据库的链接
const db = mysql.createPool({
  host: "127.0.0.1", // 数据库的ip地址
  user: "root", // 登录数据库的账号
  password: "", // 登录数据库的密码
  database: "my_db_01", //指定要操作的数据库
});

module.exports = db;

3、 创建一个用户表

在这里插入图片描述

4、初始化用户模块 router_handler模块在后续 router/user.js

const { Router } = require("express");

const router = Router();

// 导入user模块路由的处理函数
const userHandle = require("../router_handler/user");

// 注册新用户
router.post("/reguser", userHandle.regUser);
// 登录
router.post("/login", userHandle.login);

module.exports = router;


5、把router模块引入app.js

// 导入用户模块
const userRouter = require("./rooter/user");
// /api请求前缀  user模块中的所有请求都要在前面加上/api
app.use("/api", userRouter);

4、抽离用户模块中的处理函数

目的:为了保证 路由模块 的纯粹性,所有的 路由处理函数 ,必须抽离到对应的 路由处理函数模块 中

1.在 /router_handler/user.js 中,使用 exports 对象,分别向外共享如下两个 路由处理函数

exports.regUser = (req, res) => {
  res.send("reguuser ok");
};
exports.login = (req, res) => {
  res.send("login ok");
};

三、优化

1、对用户数据进行校验

目的:为了保证 路由模块 的纯粹性,所有的 校验函数 ,必须抽离到对应的 校验处理函数模块 中

在根目录下创建schema目录,在其下新建user.js文件

// 导入定义验证的包
const joi = require("joi");

// 定义用户名和密码的验证规则
const username = joi.string().alphanum().min(1).max(10).required();
const password = joi
  .string()
  .pattern(/^[\S]{6,12}$/)
  .required();

//定义验证注册和登录表单数据的对象
exports.reg_login_schma = {
  body: {
    username,
    password,
  },
};

2、对rooter模块中的 user.js 增加校验方法

const { Router } = require("express");
const router = Router();
const expressJoi = require("@escook/express-joi");

// 导入user模块路由的处理函数
const userHandle = require("../router_handler/user");
// 导入登录验证

const { reg_login_schma } = require("../schema/user");

// 1、导入验证数据的中间件

// 注册新用户
router.post("/reguser", expressJoi(reg_login_schma), userHandle.regUser);

router.post("/login", userHandle.login);

module.exports = router;

3、封装一个全局错误中间件

// 封装res.custom_err 函数 处理错误情况
app.use((req, res, next) => {
  // status =0 为成功  status=1为失灵
  // err的值,可能是一个错误对象,也可能是一个错误的描述字符串
  res.custom_err = (err, status = 1) => {
    res.send({
      status,
      message: err instanceof Error ? err.message : err,
    });
  };
  next();
});

4、在app.js中注册全局中间件注意res.custom_err 是我封装的方法 见其上

const joi = require("joi");
app.use((err, req, res, next) => {
  // 4.1 Joi 参数校验失败
  if (err instanceof joi.ValidationError) return res.custom_err(err);
  // // 4.2 未知错误
  res.custom_err(err);
});

完整代码
在这里插入图片描述

db/index.js

const mysql = require("mysql2");

// 2、建立与mysql 数据库的链接
const db = mysql.createPool({
  host: "127.0.0.1", // 数据库的ip地址
  user: "root", // 登录数据库的账号
  password: ".", // 登录数据库的密码
  database: "my_db_01", //指定要操作的数据库
});

module.exports = db;

rooter/user.js

const { Router } = require("express");
const router = Router();

const expressJoi = require("@escook/express-joi");

// 导入user模块路由的处理函数
const userHandle = require("../router_handler/user");
// 导入登录验证

const { reg_login_schma } = require("../schema/user");

// 1、导入验证数据的中间件

// 注册新用户
router.post("/reguser", expressJoi(reg_login_schma), userHandle.regUser);

router.post("/login", userHandle.login);

module.exports = router;

router_handler/user.js

const db = require("../db/index");

// 导入加密

const bcryptjs = require("bcryptjs");

exports.regUser = (req, res) => {
  const userInfo = req.body;

  if (!userInfo.username || !userInfo.password)
    return res.custom_err("账号或密码不能为空");

  const sqlStr = "select * from ev_users where username=?";
  db.query(sqlStr, userInfo.username, (err, results) => {
    if (err) return res.custom_err(err);

    // 如果>0 便是已存在
    if (results.length > 0) {
      return res.custom_err("用户名被占用");
    }
    // 在注册用户的处理函数中,确认用户名可用之后,调用 bcrypt.hashsync(明文密码,随机盐的长度)方法,对用户的密码进行加密处理
    userInfo.password = bcryptjs.hashSync(userInfo.password, 10);

    db.query("insert into ev_users set ?", userInfo, (err, results) => {
      if (err) return res.custom_err(err);

      // 判断影响行数是否为1
      if (results.affectedRows !== 1)
        res.custom_err("注册用户失败,请稍后再试");

      res.send({
        status: 0,
        msg: "注册成功",
      });
    });
  });
};
exports.login = (req, res) => {
  res.send("login ok");
};

schema/user.js

// 导入定义验证的包
const joi = require("joi");

// 定义用户名和密码的验证规则
const username = joi.string().alphanum().min(1).max(10).required();
const password = joi
  .string()
  .pattern(/^[\S]{6,12}$/)
  .required();

//定义验证注册和登录表单数据的对象
exports.reg_login_schma = {
  body: {
    username,
    password,
  },
};

app.js

// 引入 express 框架
const express = require("express");

const cors = require("cors");

const joi = require("joi");

const app = express();
// 将cors 注册成全局中间件
app.use(cors());

// 没有配置json 返回的时undefined   没有配置urlencoded 返回的时{}
// 配置解析application/x-www-form-urlencoded(表单数据)的中间件
app.use(express.urlencoded({ extended: false }));

// 配置json数据的中间件
app.use(express.json());

const port = 3000;

// 封装res.custom_err 函数 处理错误情况
app.use((req, res, next) => {
  // status =0 为成功  status=1为失灵
  // err的值,可能是一个错误对象,也可能是一个错误的描述字符串
  res.custom_err = (err, status = 1) => {
    res.send({
      status,
      message: err instanceof Error ? err.message : err,
    });
  };
  next();
});


// 导入用户模块
const userRouter = require("./rooter/user");
// /api请求前缀
app.use("/api", userRouter);




// 错误中间件 应该放到最后
app.use((err, req, res, next) => {
  // 4.1 Joi 参数校验失败
  if (err instanceof joi.ValidationError) return res.custom_err(err);
  // // 4.2 未知错误
  res.custom_err(err);
});

app.listen(port, () => console.log(`Example app listening on port ${port}!`));

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2242766.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Shell基础(4)

声明! 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团…

(长期更新)《零基础入门 ArcGIS(ArcMap) 》实验一(下)----空间数据的编辑与处理(超超超详细!!!)

续上篇博客(长期更新)《零基础入门 ArcGIS(ArcMap) 》实验一(上)----空间数据的编辑与处理(超超超详细!!!)-CSDN博客 继续更新 本篇博客内容为道路拓扑检查与修正&#x…

Python防检测之鼠标移动轨迹算法

一.简介 鼠标轨迹算法是一种模拟人类鼠标操作的程序,它能够模拟出自然而真实的鼠标移动路径。 鼠标轨迹算法的底层实现采用C/C语言,原因在于C/C提供了高性能的执行能力和直接访问操作系统底层资源的能力。 鼠标轨迹算法具有以下优势: 模拟…

3D编辑器教程:如何实现3D模型多材质定制效果?

想要实现下图这样的产品DIY定制效果,该如何实现? 可以使用51建模网线上3D编辑器的材质替换功能,为产品3D模型每个部位添加多套材质贴图,从而让3D模型在展示时实现DIY定制效果。 具体操作流程如下: 第1步:上…

Qt按钮类-->day09

按钮基类 QAbstractButton 标题与图标 // 参数text的内容显示到按钮上 void QAbstractButton::setText(const QString &text); // 得到按钮上显示的文本内容, 函数的返回就是 QString QAbstractButton::text() const;// 得到按钮设置的图标 QIcon icon() const; // 给按钮…

Cellebrite VS IOS18Rebooting

Cellebrite VS IOS18Rebooting我们想分享一些有关 iOS 18 重启“功能”的信息。在过去一周左右的时间里,人们对 iOS 18 中一项新的未记录功能产生了极大关注,该功能会导致设备在一段时间不活动后重新启动。 这意味着,如果设备在一定时间不活…

【Linux】:进程信号(详谈信号捕捉 OS 运行)

✨ 来去都是自由风,该相逢的人总会相逢 🌏 📃个人主页:island1314 🔥个人专栏:Linux—登神长阶 ⛺️ 欢迎关注:👍点赞…

视觉SLAM相机——单目相机、双目相机、深度相机

一、单目相机 只使用一个摄像头进行SLAM的做法称为单目SLAM,这种传感器的结构特别简单,成本特别低,单目相机的数据:照片。照片本质上是拍摄某个场景在相机的成像平面上留下的一个投影。它以二维的形式记录了三维的世界。这个过程中…

MongoDB在现代Web开发中的应用

💓 博客主页:瑕疵的CSDN主页 📝 Gitee主页:瑕疵的gitee主页 ⏩ 文章专栏:《热点资讯》 MongoDB在现代Web开发中的应用 MongoDB在现代Web开发中的应用 MongoDB在现代Web开发中的应用 引言 MongoDB 概述 定义与原理 发展…

OceanBase 分区表详解

1、分区表的定义 在OceanBase数据库中,普通的表数据可以根据预设的规则被分割并存储到不同的数据区块中,同一区块的数据是在一个物理存储上。这样被分区块的表被称为分区表,而其中的每一个独立的数据区块则被称为一个分区。 如下图所示&…

Linux(CentOS 7) yum一键安装mysql8

1、通过yum安装 (1)下载mysql 在Linux找个地方输入以下命令 wget https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm (2)安装mysql yum 仓库配置文件 [rootVM-8-15-centos ~]# sudo rpm -Uvh mysql80-c…

记一次预览USB摄像头并获取实时回调数据的过程(UVCAndroid集成)

背景 主工程是gradle4.8 jdk1.8 启用jetifier要接入的usb摄像头的库是UVCAndroid gradle8.7 jdk17 接入过程 看了下setCallbackActivity非常适合我们的需求,而且回调后的数据是RGB888,看到demo中用到了xml若干于是想到用aar打包,整个过程也…

shell脚本_永久环境变量和字符串操作

一、永久环境变量 1. 常见的环境变量 2. 设置永久环境变量 3.1.将脚本加进PATH变量的目录中 3.2.添加进环境变量里 3.2.修改用户的 shell 配置文件 二、字符串操作 1. 字符串拼接 2. 字符串切片 3. 字符串查找 4. 字符串替换 5. 字符串大小写转换 6. 字符串分割 7…

操作系统进程管理实验

父子进程 用系统调用fork()函数实现子进程的创建&#xff0c;熟悉进程创建的执行过程。 #include <stdio.h> #include <stdlib.h> #include <unistd.h>int main() {// 打印主进程的 PIDprintf("hello, world (pid: %d)\n", (int)getpid());// 创…

DB Type

P位 p 1时段描述符有效&#xff0c;p 0时段描述符无效 Base Base被分成了三个部分&#xff0c;按照实际拼接即可 G位 如果G 0 说明描述符中Limit的单位是字节&#xff0c;如果是G 1 &#xff0c;那么limit的描述的单位是页也就是4kb S位 S 1 表示代码段或者数据段描…

获取当前程序运行时的栈大小[C语言]

废话前言 一晃已经毕业了4年&#xff0c;也在某个时间点&#xff0c;从面试者转变成了面试官。 进行第一次面试的时候&#xff0c;我好像比候选人还慌张&#xff0c;压根不知道问什么&#xff0c;好在是同行业&#xff0c;看着简历问了一些协议内容以及模块设计思路&#xff0…

新160个crackme - 098-DueList.4

运行分析 需破解Name和Code PE分析 ASM汇编程序&#xff0c;32位&#xff0c;无壳 静态分析&动态调试 ida搜索找到关键字符串 ida动态调试&#xff0c;逻辑如上 算法分析 Name concealstr_1 SU7CSJKF09NCSDO9SDF09SDRLVK7809S4NF str_2 A1LSK2DJF4HGP3QWO5EIR6UTYZ8MXN…

ETH钱包地址如何获取 如何购买比特币

首先我们要先注册一个交易所 Gate.io&#xff08;推荐&#xff09;: 点我注册 1、注册很简单&#xff0c;通过手机号就可以进行注册了。 2、获取ETH钱包地址 注册好之后&#xff0c;如图所示&#xff0c;点击“统一账户” 3、通过搜索栏搜索ETH&#xff0c;如下图所示 4、点…

【HOT100第五天】搜索二维矩阵 II,相交链表,反转链表,回文链表

240.搜索二维矩阵 II 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&#xff1a; 每行的元素从左到右升序排列。每列的元素从上到下升序排列。 先动手写写最简单方法&#xff0c;二重循环。 class Solution { public:bool searchMa…

.NET 9与C# 13革新:新数据类型与语法糖深度解析

记录&#xff08;Record&#xff09;类型 使用方式&#xff1a; public record Person(string FirstName, string LastName); 适用场景&#xff1a;当需要创建不可变的数据结构&#xff0c;且希望自动生成 GetHashCode 和 Equals 方法时。不适用场景&#xff1a;当数据结构需…