目录设计routes存放路由 controller存放控制器 services管理model层 router->controller-services->mysql
3-1 公共配置
错误信息管理
根据接口错误 返回对应错误信息
src/constants/errorInfo.ts
/*** @description 失败信息集合,包括 code 和 message* @author 拔都*/export default {// 用户名已存在registerUserNameExistInfo: {code: 10001,message: '用户名已存在'},// 注册失败registerFailInfo: {code: 10002,message: '注册失败,请重试'},// 用户名不存在registerUserNameNotExistInfo: {code: 10003,message: '用户名未存在'},// 登录失败loginFailInfo: {code: 10004,message: '登录失败,用户名或密码错误'},// 未登录loginCheckFailInfo: {code: 10005,message: '您尚未登录'},// 修改密码失败changePasswordFailInfo: {code: 10006,message: '修改密码失败,请重试'},// 用户信息失败getUserInfoFailInfo: {code: 10007,message: '用户信息获取失败 token验证无效'},getUserListFailInfo: {code: 10008,message: '用户列表获取失败, 请重试'},editUserInfoFailInfo: {code: 10009,message: '用户信息修改失败, 请重试'},deleteUserInfoFailInfo: {code: 10010,message: '用户删除失败, 请重试'},updateUserRoleFailInfo: {code: 10011,message: '用户角色修改失败,请重试'}}
存放密钥
src/config/auth.ts
// jwt加密用export const jwtSecret = 'vue3-admin-jwt'// MD5加密用(比如用户密码 需要加密后再存放到数据库)export const userSecret = 'vue3-admin-user-password'
响应封装
创建成功和失败两个响应类
src/utils/Response.ts
// 请求响应封装interface ResponseData {code: number;data?: any;message?: string;}class BaseResponse {public code!: number;public data: any;public message!: string;constructor({ code, data, message }: ResponseData) {this.code = codeif (data) this.data = dataif (message) this.message = message}}export class SuccessResponse extends BaseResponse {constructor(data: any) {super({code: 0,data})}}export class ErrorResponse extends BaseResponse {constructor(code: number, message: string) {super({code,message})}}
md5加密方法
src/utils/createMD5.ts
import crypto from 'crypto'import { userSecret } from '../config/auth'// md5加密export const createMd5 = (content: any) => {const md5 = crypto.createHash('md5')return md5.update(`${content}_${userSecret}`).digest('hex')}
初始tsconfig.json
tsc --init
3-2 开发注册接口
效果图
user表目前是空

发送注册请求
注册后:
再次点击注册 重复注册
创建auth路由
auth里的路由负责用户登录注册认证和用户信息获取

src/routes/auth.ts
route里需要调相应controller
import Router from '@koa/router'import { registerController } from '../controller/auth'const router = new Router({prefix: '/api/auth'})/*** 用户注册接口* /auth/register*/router.post('/register', async ctx => {ctx.body = await registerController(ctx.request.body)})export default router
创建controller
src/controller/auth.ts
import { RegisterModel } from '../db/models/user'import { createUser, getUserInfo } from '../services/auth'import { ErrorResponse, SuccessResponse } from '../utils/Response'import errorInfo from '../constants/errorInfo'import { createMd5 } from '../utils/createMD5'const {registerUserNameExistInfo,registerFailInfo} = errorInfoexport const registerController = async (params: RegisterModel) => {const { username, password } = params// 注册前先看下用户是否已注册 getUserInfo servicesconst userInfo = await getUserInfo({ username })if (userInfo) { // 如果已注册// 用户已注册const { code, message } = registerUserNameExistInforeturn new ErrorResponse(code, message)}// 用户不存在try {await createUser({ // 创建用户...params,password: createMd5(password)})return new SuccessResponse({})} catch (err) { // 注册失败console.log(err.message, err.stack)const { code, message } = registerFailInforeturn new ErrorResponse(code, message)}}
创建services
src/services/types.ts
services下类型管理
export interface UserWhereProps {username: string;password?: string;id?: number;}
src/services/auth.ts
import UserModel, { RegisterModel, UserModelProps } from '../db/models/user'import { UserWhereProps } from './types'import { createMd5 } from '../utils/createMD5'/*** 创建用户*/export const createUser = async ({ username, password, email, mobile, status, avatar }: RegisterModel) => {const result = await UserModel.create({username,password,email,mobile,status})return result.toJSON()}/*** 根据用户名 获取用户信息* @param username 用户名* @param password 密码* @param id 用户id* @returns 用户信息*/export const getUserInfo = async ({ username, password, id }: UserWhereProps): Promise<UserModelProps | null> => {const where: UserWhereProps = {username}if (password) {where.password = createMd5(password)}if (typeof id != 'undefined') {where.id = id}const result = await UserModel.findOne({attributes: {exclude: ['password', 'createdAt', 'updatedAt']},where,})if (result == null) return nullreturn result.toJSON() as UserModelProps}
models/user.ts 类型声明小修改
注册插入数据时,允许avatar字段可选,后续 我们可以在个人设置里修改上传

import {Model,DataTypes,Optional} from 'sequelize'import seq from '../seq'// sequelize+typescript 参考文档// https://sequelize.org/master/manual/typescript.html// model类型export interface UserModelProps {id: number;username: string;password: string;email: string | null;mobile: string | null;avatar: string;isSuper: 0 | 1;status: 0 | 1;}// 注册接口params类型 id 和 isSuper创建时候可以不用定义自动分配export type RegisterModel = Omit<UserModelProps, 'id'|'isSuper'>// 在“User.build”和“User.create”调用中,有些属性是可选的interface UserCreationAttributes extends Optional<UserModelProps, "id" | "isSuper" | "status" | "avatar"> {}// Model实例接口interface UserInstanceextends Model<UserModelProps, UserCreationAttributes>,UserModelProps {}// 创建User模型 数据表的名字是usersconst User = seq.define<UserInstance>('User', {id: {primaryKey: true,type: DataTypes.INTEGER.UNSIGNED,autoIncrement: true},// id会自动创建 并设为主键、自增username: {type: DataTypes.STRING,allowNull: false,comment: '用户名'},password: {type: DataTypes.STRING,allowNull: false,comment: '密码'},email: {type: DataTypes.STRING,comment: '用户邮箱'},mobile: {type: DataTypes.STRING,comment: '手机号'},avatar: {type: DataTypes.STRING,comment: '头像'},isSuper: {type: DataTypes.BOOLEAN, // TINYINT(1)comment: '超级管理员 1是 0不是',defaultValue: 0},status: {type: DataTypes.BOOLEAN, // TINYINT(1)comment: '账户禁用状态 1正常 0禁用',defaultValue: 1}})export default User
本节参考源码
https://gitee.com/brolly/vue3-admin-server/commit/b5e87e90202de55937fef9ac9140cbc7433ee737
