Koa学习3:用户添加、错误处理
模型
在src
目录下创建model
目录,用来存放模型
创建用户模型
user.model.js
注意: UUID
类型是无法自增的,将id设置为UUID
类型时只需要为其指定默认值即可
// 数据类型
const { DataTypes } = require('sequelize');
// 导入已经连接了数据库的Sequlize对象
const sequelize = require('../db/seq');// 创建模型
const User = sequelize.define('zd_user', // 对应数据库里的表,默认会变成复数形式也就是 zd_users// 定义模型的属性(表的字段){// id会被自动创建,也可以不定义id: {type: DataTypes.UUID, // UUID 类型unique: true, // 是否唯一primaryKey: true, // 是否是主键comment: '主键', // 注释defaultValue:DataTypes.UUIDV4 // 设置uuid的生成规则},// 用户名user_name: {type: DataTypes.STRING, // 对应VARCHAR(255)unique: true,allowNull: false,comment: '用户名',// 验证器,用于校验格式,具体见官方文档validate: {isAlphanumeric: true, // 仅允许字符和数字len: [6, 10], //长度},},// 密码password: {type: DataTypes.CHAR(64),allowNull: false,comment: '密码',validate: {isAlphanumeric: true, // 仅允许字符和数字len: [6, 10], //长度},},// 是否是vipis_vip: {type: DataTypes.BOOLEAN,allowNull: false,defaultValue: 0, // 默认值,BOOLEAN类型的值只有0和1,填写true和false也会被自动转换comment: '是否是vip',},}
);// 模型同步,将创建表,如果表已经存在,则将其首先删除
// User.sync({ force: true });module.exports = User;
在项目根目录下运行该js
文件,创建表(要在项目根目录下,不然无法读取到.env中的变量)
默认情况下,Sequelize 使用数据类型 DataTypes.DATE 自动向每个模型添加 createdAt 和 updatedAt 字段. 这些字段会自动进行管理 - 每当你使用Sequelize 创建或更新内容时,这些字段都会被自动设置. createdAt 字段将包含代表创建时刻的时间戳,而 updatedAt 字段将包含最新更新的时间戳.
注意: 这是在 Sequelize 级别完成的(即未使用 SQL触发器 完成). 这意味着直接 SQL 查询(例如,通过任何其他方式在不使用 Sequelize 的情况下执行的查询)将不会导致这些字段自动更新.
如果不想要下面这两个字段可以设置timestamps
为false
sequelize.define('User', {// ... (属性)
}, {timestamps: false
});
添加用户
user.service
// 导入用户模型
const User = require('../model/user.model');
class UserService {// 创建用户async createUser(user_name, password) {// 插入数据,新增成功后会返回该条数据的对象const res = await User.create({ user_name, password });return res;}// 获取用户基本信息async getUserInfo(params = { id, user_name, is_vip }) {// 处理where条件const whereOpt = {};for (let key in params) {if (![undefined, null, ''].includes(params[key])) {whereOpt[key] = params[key];}}// 查询符合条件的第一条数据const res = await User.findOne({// 指定要返回的属性attributes: ['id', 'user_name', 'is_vip', 'createdAt', 'updatedAt'],// where条件where: whereOpt,});return res ? res : null;}
}// 导出
module.exports = new UserService();
user.controller
/*** 处理与用户有关的请求*///导入service
const { createUser, getUserInfo } = require('../service/user.service');class UserController {//注册async register(ctx, next) {// 1、获取数据const requistBody = ctx.request.body;// 合法性判断if (!requistBody.user_name || !requistBody.password) {console.error('用户名或密码为空');ctx.body = {code: '10001', // 错误code,用于定义错误类型,团队内部自行约定message: '用户名或密码为空',data: null,};return;}// 合理性,判断该用户是否已经存在,用户名是唯一的if (await getUserInfo({ user_name:requistBody.user_name })) {ctx.body = {code: '10002',message: '该用户已存在,请勿重新注册',data: null,};return;}// 2、操作数据库const res = await createUser(requistBody.user_name, requistBody.password);// 3、返回响应结果ctx.body = {code: 0,message: '用户创建成功',data: null,};}// 登录async login(ctx, next) {ctx.body = '登录';}
}// 导出实例化对象
module.exports = new UserController();
需要注意,当输入文本之类的信息时要避免字符串中的特殊字符,需要将其转义为HTML实体,避免恶意脚本注入。
const str = "<script>alert('hello world');</script>";
const escapedStr = sequelize.escape(str);
console.log(escapedStr); // 输出:"<script>alert('hello world');</script>"
错误处理
从上面的代码可以看到对于错误处理并不完善可能会出现一些其他的错误,并且如果每一个接口都要这样写的话是很难维护的,因此需要一个中间件进行统一的错误处理。
在src
下创建一个constant
用来定义一些常量,创建一个middleware
文件夹用来存放错误处理的逻辑
错误类型
constant/user.err.type.js
用于记录与用户有关的错误类型
module.exports={userFormatError:{code: '10001', // 错误code,用于定义错误类型,团队内部自行约定message: '用户名或密码为空',data: null,},userAlreadyExisted:{code: '10002',message: '该用户已存在,请勿重新注册',data: null,},userRegisterErr:{code: '10003',message: '用户注册失败',data: null,}
}
constant/err.type.js
错误类型的统一出口,后续会加一些其他的错误类型
// 用户错误
const UserErr = require('./user.err.type');module.exports = {UserErr,
};
中间件
middleware/user.middleware.js
// 导入service层
const { getUserInfo } = require('../service/user.service');
// 导入错误类型
const { UserErr } = require('../constant/err.type');// 用户注册校验
const userRegisterValidator = async (ctx, next) => {// 获取入参const requistBody = ctx.request.body;// 合法性判断if (!requistBody.user_name || !requistBody.password) {// console.error 打印的内容会被记录到服务器的日志里console.error('用户名或密码为空:', requistBody);//使用了Koa的错误处理机制ctx.app.emit('error', UserErr.userFormatError, ctx);return;}// 合理性,判断该用户是否已经存在,用户名是唯一的if (await getUserInfo({ user_name: requistBody.user_name })) {console.error('该用户已存在,请勿重新注册:', requistBody);ctx.app.emit('error', UserErr.userAlreadyExisted, ctx);return;}// 验证通过后交由一个中间件处理await next();
};module.exports = {userRegisterValidator,
};
注意:
- console.error 打印的内容会被记录到服务器的日志里;
ctx.app.emit('error', UserErr.userAlreadyExisted, ctx)
,使用koa提供的错误机制让 Koa 自动捕获错误并返回给客户端
使用
router/user.route.js
// 注册
router.post('/register', userRegisterValidator, register);
先执行userRegisterValidator
中间件进行注册校验,校验通过后在执行register
中间件进行注册
app/index.js
const app = new Koa();
// koa-body中间件要在所有的路由之前
app.use(koaBody());// 中间件
app.use(userRouter.routes());// 进行统一的错误处理
app.on('error', (errType, ctx) => {ctx.body = errType;
});module.exports = app;
相关文章:

Koa学习3:用户添加、错误处理
模型 在src目录下创建model目录,用来存放模型 创建用户模型 user.model.js 注意: UUID类型是无法自增的,将id设置为UUID类型时只需要为其指定默认值即可 // 数据类型 const { DataTypes } require(sequelize); // 导入已经连接了数据库…...

网络安全入门学习第十五课——PHP基础
文章目录 一、WEB技术1、什么是web2、B/S架构3、C/S架构 二、PHP概述1、PHP是什么2、PHP受欢迎的原因3、基于MVC模式的PHP框架4、常用编译工具5、PHP环境搭建6、开发工具 三、PHP基本语法格式1、标记2、输出语句3、注释4、标识符 四、数据与运算1、常量1.1、常量定义1.2、预定义…...

电子科技大学 数学专业-功不唐捐,玉汝于成
电子科技大学 数学专业 功不唐捐,玉汝于成 1.本科背景 本科是坐落于湖南湘潭的湖南科技大学,专业为网络工程专业,因热爱数学专业,所以决定跨考数学专业。 本科专业课平均成绩85,排名10/104。CET 4 474分,…...
Android10.0 iptables用IOemNetd实现删除子链功能的实现
1.前言 在10.0的系统rom定制化开发中,在system中netd网络这块的产品需要中,会要求设置屏蔽ip地址之内的功能, liunx中iptables命令也是比较重要的,接下来就来在IOemNetd这块实现删除创建子链的相关功能 2. iptables用IOemNetd实现删除创建子链功能的实现的核心类 syste…...

OpenGL光照之光照贴图
文章目录 漫反射贴图镜面光贴图放射光贴图代码 每个物体都拥有自己独特的材质从而对光照做出不同的反应的方法。这样子能够很容易在一个光照的场景中给每个物体一个独特的外观,但是这仍不能对一个物体的视觉输出提供足够多的灵活性。 我们将整个物体的材质定义为一个…...

2018~2019 学年第二学期《信息安全》考试试题(B 卷)
北京信息科技大学 2018 ~2019 学年第 2 学期 《信息安全》课程期末考试试卷 B 课程所在学院:计算机学院 适用专业班级:计科 1601-06,重修 考试形式:(闭卷) 一. 选择题(本题满分 10 分,共含 10 道小题,每小题 1 分) 网络中存在的安全漏洞主…...
LeetCode-C#-0002.两数相加
0.声明 该题目来源于LeetCode 如有侵权,立马删除。 解法不唯一,如有新解法可一同讨论。 1.题目 0002两数相加 给你两个非空的链表,表示两个非负的整数,它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储一…...

访问修饰符private,default,protected,public访问等级区别
private:private是最严格的访问修饰符,它将成员声明为私有的。私有成员只能在声明它们的类内部访问,其他类无法直接访问私有成员。这样可以确保数据的封装性和安全性。 default(默认):如果没有明确指定访问…...

阿里云(Linux)安装Docker教程
首先安装docker,需要找到帮助文档,那肯定是我们的官网: Install Docker Engine on CentOS | Docker Documentation 找到对应的位置,这里是安装在CentOS中,版本需要Ce…...
Linux C编程基础:获取时间
1.前言 对于linux下的编程,无论是用户态还是内核态,时间获取都是经常需要使用到的。以下分别从用户态和内核态整理了几个常用的时间获取接口,供编写代码时快速查阅。 2.用户态获取时间 2.1 clock_gettime() #include <time.h>int c…...
Spring核心注解
1、Bean注解 作用:用于把当前方法的返回值作为bean对象存入spring的ioc容器中位置: 一般出现在方法上面属性: name:用于指定bean的id。当不写时,默认值是当前方法的名称细节:当我们使用注解配置方法时,如果方法有参数,…...

哈希表原理,以及unordered_set/和unordered_map的封装和迭代器的实现
哈希表 unordered系列unordered_set和unordered_map的使用哈希哈希概念哈希冲突哈希函数闭散列开散列哈希表的扩容哈希表源码(开散列和闭散列) 封装unordered_set/和unordered_map,以及实现迭代器节点定义unordered_set定义unordered_map定义…...

如何把歌曲里的伴奏音乐提取出来,分享几个方法给大家!
对于一首歌,我们都知道,它有两部分组成:背景音乐人声。这两者合在一起,便是我们经常听的歌。部分用户想要直接获取歌曲伴奏,那么可以在UU伴奏网上下载。 操作方法比较简单,直接搜索想要的歌曲名称就可以了…...

区块链产业快速发展 和数集团开启区块链应用新时代
UTONMOS区块链游戏要来了。 就在5月底,UTONMOS品牌所属公司上海和数集团在泰国发布了【神念无界】系列的多款国际版链游,包括【神念无界-源起山海】、【北荒传奇】、【神宠岛】、【神农园】等区块链游戏。 以【神念无界-源起山海】为例,其是…...
初出茅庐的小李博客之常见字符串函数使用
C语言字符数组与字符串数组 在C语言中,字符数组和字符串数组实际上是同一种类型。字符串是由字符组成的字符数组,通常以空字符 ‘\0’ 结尾。C语言中的字符串是一种常见的数据类型。我们可以通过两种方式定义字符数组跟字符串数组 char charArray[10];…...
运筹学工程化流程和常见的运筹学算法分类以及常见软件
文章目录 前言运筹学工程化流程运筹学算法分类运筹学软件参考文献 前言 自2023年初新冠疫情管控放开后,各家公司各类岗位的人员都有被裁的消息传出,但用人市场上运筹学算法岗位却反其道行之,用工出现了激增。可以预见的是数据算法将从传统的…...

JAVA面向对象(三)
第三章 封装与继承 目录 第三章 封装与继承 1.1.封装 1.2.包 1.3.访问权限控制 1.4.static修饰符 1.4.1.成员变量 1.4.2.成员方法 1.4.3.代码块 总结 内容仅供学习交流,如有问题请留言或私信!!!!࿰…...
前端面试题---跨域处理和异常、错误处理
一.跨域处理 在前端开发中,当我们在浏览器中向不同域名或端口发起请求时,就会遇到跨域请求的限制。为了处理跨域请求,有几种常见的方法 1.JSONP(JSON with Padding) JSONP是一种利用 <script> 标签可以跨域加载…...

网络安全之反序列化漏洞分析
简介 FastJson 是 alibaba 的一款开源 JSON 解析库,可用于将 Java 对象转换为其 JSON 表示形式,也可以用于将 JSON 字符串转换为等效的 Java 对象分别通过toJSONString和parseObject/parse来实现序列化和反序列化。 使用 对于序列化的方法toJSONStrin…...
19 贝叶斯线性回归
文章目录 19 贝叶斯线性回归19.1 频率派线性回归19.2 Bayesian Method19.2.1 Inference问题19.2.2 Prediction问题 19 贝叶斯线性回归 19.1 频率派线性回归 数据与模型: 样本: { ( x i , y i ) } i 1 N , x i ∈ R p , y i ∈ R p {\lbrace (x_i, y_…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...

云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...