目录设计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 = code
if (data) this.data = data
if (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
} = errorInfo
export const registerController = async (params: RegisterModel) => {
const { username, password } = params
// 注册前先看下用户是否已注册 getUserInfo services
const userInfo = await getUserInfo({ username })
if (userInfo) { // 如果已注册
// 用户已注册
const { code, message } = registerUserNameExistInfo
return 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 } = registerFailInfo
return 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 null
return 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 UserInstance
extends Model<UserModelProps, UserCreationAttributes>,
UserModelProps {}
// 创建User模型 数据表的名字是users
const 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