用户注册接口设计
① 编写流程
- 注册用户路由router编写;
- 处理函数的控制器controller编写;
- 操作数据库的service编写;
采用分层架构的思维,不同的模块处理不同的内容。
注意:需要安装koa对body解析的依赖
//目录:@/oruter/index.js // 封装路由 const fs = require ('fs') const useRoutes = function (){ fs.readdirSync(__dirname).forEach(file=>{ if(file === 'index.js') return; const router = require(`./${file}`) this.use(router.routes()); this.use(router.allowedMethods()) }) } module.exports = useRoutes
//目录:@/app/index.js const Koa = require("koa") const bodyParser = require("koa-bodyparser") const useRoutes = require('../router') // 创建路由 const errorHandler = require('./error_handle') // 错误处理文件 const app = new Koa() app.useRoutes = useRoutes; app.use(bodyParser()) app.useRoutes() app.on('error',errorHandler) //触发错误处理函数 module.exports = app
② 注册用户路由
// 目录: @/router/user_router.js const Router = require("koa-router") const { create } = require("../controller/user_controller") const userRouter = new Router({ prefix: "/users" }) userRouter.post("/", create) module.exports = userRouter
③ 控制层处理函数
// 目录: @/controller/user_controller.js const userService = require("../service/user_service") class UserController { // 创建用户 async create(ctx, next) { const user = ctx.request.body const results = await userService.create(user) ctx.body = results } } module.exports = new UserController()
④ 数据库操作
先编写数据库操作语句,后面单独将数据库连接处理
// 目录: @/service/user_service.js const connection = require("../app/database") class UserService { async create(user) { // 将user储存到用户表中 const statement = `INSERT INTO user (name,password) VALUES(?,?);` // console.log("用户存入数据库成功"); return results[0] } } module.exports = new UserService()
连接Mysql数据库
① 安装 mysql2
npm install mysql2
② 连接数据库
这里的环境变量需要自己在.env环境配置文件中填写,这样只需要在.env文件中修改数据库配置信息就可以了。
// 目录: @/app/database.js // 完整的数据库连接配置 const mysql = require('mysql2') const config = require('./config') const connections = mysql.createPool({ host: config.MYSQL_HOST, port: config.MYSQL_PORT, database: config.MYSQL_DATABASE, user: config.MYSQL_USER, password: config.MYSQL_PASSWORD }); connections.getConnection((err,conn)=>{ conn.connect((err)=>{ if(err){ console.log('连接数据库失败',err); }else( console.log('连接数据库成功') ) }) }) module.exports = connections.promise();
注册用户校验
编写用户注册的中间件,用户写入用户名和密码,编写中间件verifyUser判断用户是否已经存在在数据库中。
① 创建数据库用户表① 创建数据库用户表
① 创建数据库用户表
# 创建用户表 CREATE TABLE IF NOT EXISTS `user`( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(30) NOT NULL UNIQUE, password VARCHAR(50) NOT NULL, createAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updateAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP );
② 创建错误信息处理文件
独立编写一个错误常量文件(完整)(@/app/error_handle.js)
// 目录: @/constants/error_types.js const NAME_OR_PASSWORD_IS_REQUIRED = 'name_or_password_is_required'; const USER_ALREADY_EXISTS = 'user_already_exists'; const USER_DOES_NOT_EXISTS = 'user_does_not_exists'; const PASSWORD_IS_INCORRENT = 'password_is_incorrent'; const UNAUTHORIZATION = 'UNAUTHORIZATION'; const UNPERMISSION = 'unpermission'; module.exports = { NAME_OR_PASSWORD_IS_REQUIRED, USER_ALREADY_EXISTS, USER_DOES_NOT_EXISTS, PASSWORD_IS_INCORRENT, UNAUTHORIZATION, UNPERMISSION }
const errorTypes = require('../constants/error_types') const errorHandler = (error,ctx) =>{ // // 这里的 error.message = new Error(里面的值) let status,message; switch(error.message){ case errorTypes.NAME_OR_PASSWORD_IS_REQUIRED: // console.log(error.message); status = 400; //Bad Request message = "用户名和密码不能为空" break; case errorTypes.USER_ALREADY_EXISTS: status = 405; //conflict message = "用户名已存在" break; case errorTypes.USER_DOES_NOT_EXISTS: status = 400; //conflict message = "用户名不存在" break; case errorTypes.PASSWORD_IS_INCORRENT: status = 400; //conflict message = "密码错误" break; case errorTypes.UNAUTHORIZATION: status = 401; //unauthorization message = "token无效" break; case errorTypes.UNPERMISSION: status = 401; //unauthorization message = "您不具备权限" break; default: status = 404; message = "默认错误"; } ctx.status = status; ctx.body = message; } module.exports = errorHandler;
③ 编写验证用户是否存在中间件
// 目录: @/middleware/user_middleware.js const errorTypes = require("../constants/error_types") const serviece = require("../service/user_service") const verifyUser = async (ctx, next) => { console.log("用户注册验证middleware") // 1.获取用户名和密码 const { name, password } = ctx.request.body // console.log(name,password); // 2.判断用户名或者密码不能为空 if (!name || !password || name === "" || password === "") { const error = new Error(errorTypes.NAME_OR_PASSWORD_IS_REQUIRED) // // 发射错误信息 // console.log(error); return ctx.app.emit("error", error, ctx) } // 3.判断这次注册的用户名是注册过的 const results = await serviece.getUserByName(name) if (results.length) { const error = new Error(errorTypes.USER_ALREADY_EXISTS) return ctx.app.emit("error", error, ctx) } await next() } module.exports = { verifyUser }
// 目录: @/service/user_service.js // 查询用户是否存在数据库中 async getUserByName(name) { const statement = `SELECT *FROM user WHERE name = ?;` const results = await connection.execute(statement, [name]) return results[0] }
④ MD5加密密码
将用户注册的密码拦截之后加密,再存储到数据库中,防止数据库泄露,这里采用MD5加密
npm install blueimp-md5
创建 handlePassword 函数,在user_middleware.js中中间件verifyUser中插入
const handlePassword = async (ctx, next) => { const { password } = ctx.request.body ctx.request.body.password = md5password(password) await next() }
创建工具函数,处理MD5密码加密(@/utils/password_handle.js)