Koa learning 3: user addition, error handling

Model

srcCreate a directory under the directory to modelstore the model

Create a user model

user.model.js

Note: UUID The type cannot be auto-incremented. When setting the id as UUIDthe type, you only need to specify a default value for it

// 数据类型
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], //长度
      },
    },
    // 是否是vip
    is_vip: {
    
    
      type: DataTypes.BOOLEAN,
      allowNull: false,
      defaultValue: 0, // 默认值,BOOLEAN类型的值只有0和1,填写true和false也会被自动转换
      comment: '是否是vip',
    },
  }
);

// 模型同步,将创建表,如果表已经存在,则将其首先删除
// User.sync({ force: true });

module.exports = User;

Run the file in the root directory of the project jsto create a table (it must be in the root directory of the project, otherwise the variables in .env cannot be read)
insert image description here

By default, Sequelize automatically adds createdAt and updatedAt fields to each model using the data type DataTypes.DATE. These fields are managed automatically - whenever you create or update content with Sequelize, these fields are automatically set. The createdAt field will be contains a timestamp representing the moment of creation, while the updatedAt field will contain the latest updated timestamp.

NOTE: This is done at the Sequelize level (i.e. not done using SQL triggers). This means that direct SQL queries (eg, by any other means executed without using Sequelize) will not cause these fields to be automatically Update.
If you don't want the following two fields can be set timestampsto false

sequelize.define('User', {
    
    
  // ... (属性)
}, {
    
    
  timestamps: false
});

Add user

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();

g)
insert image description here

It should be noted that when entering information such as text, to avoid special characters in the string, it needs to be escaped into HTML entities to avoid malicious script injection.

const str = "<script>alert('hello world');</script>";
const escapedStr = sequelize.escape(str);
console.log(escapedStr); // 输出:"&lt;script&gt;alert(&#x27;hello world&#x27;);&lt;/script&gt;"

error handling

From the above code, we can see that some other errors may occur if the error handling is not perfect, and it is difficult to maintain if every interface has to be written in this way, so a middleware is needed for unified error handling.

srcCreate one below constantto define some constants, create a middlewarefolder to store error handling logic

error type

constant/user.err.type.jsUsed to log user-related error types

module.exports={
    
    
    userFormatError:{
    
    
        code: '10001', // 错误code,用于定义错误类型,团队内部自行约定
        message: '用户名或密码为空',
        data: null,
    },
    userAlreadyExisted:{
    
    
        code: '10002',
        message: '该用户已存在,请勿重新注册',
        data: null,
    },
    userRegisterErr:{
    
    
        code: '10003',
        message: '用户注册失败',
        data: null,
    }
}

constant/err.type.jsUnified export of error types, and some other error types will be added later

// 用户错误
const UserErr = require('./user.err.type');

module.exports = {
    
    
  UserErr,
};

middleware
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,
};

Notice:

  • The content printed by console.error will be recorded in the server's log;
  • ctx.app.emit('error', UserErr.userAlreadyExisted, ctx), use the error mechanism provided by koa to let Koa automatically catch errors and return them to the client

use
router/user.route.js

// 注册
router.post('/register', userRegisterValidator, register);

First execute the middleware for registration verification, and then execute the middleware for registration userRegisterValidatorafter the verification is passedregister

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;

Guess you like

Origin blog.csdn.net/weixin_41897680/article/details/131037829