前言
大家好,我叫竹业。今天主要来了解一下用Egg.js编写一套增删查改,以及登陆注册接口。
Egg.js 为企业级框架和应用而生,我们希望由 Egg.js 孕育出更多上层框架,帮助开发团队和开发人员降低开发和维护成本。 ---来自官方的介绍
egg工程搭建
新建一个文件,通过下面命令,一路默认回车,搭建工程
npm init egg --type=simple 安装依赖 npm i 本地启动服务 npm run dev
文件主要目录
一个简单的get请求
虽然一个简单get的请求,用express也很容易做到,但是egg让我们结构更加的清晰,遵守MVC模式,每一层
router路由配置
当访问localhost:7001/hello的路径时,会执行controller文件夹下面,home.js文件里面的index方法
// router.js
module.exports = (app) => {
const { router } = app;
router.get("/hello", controller.home.index);
};
controller层
直接返回结果(也可以在这里调用service方法,获取数据库数据)
"use strict";
const Controller = require("egg").Controller;
class HomeController extends Controller {
async index() {
const { ctx } = this;
ctx.body = "hello egg";
}
}
module.exports = HomeController;
通过postman访问接口
如何实现一套增删查改
我们实现一套标签的增删查找
配置路由
使用egg提供的RESTful风格的URL定义
| Method | Path | Route Name | Controller.Action |
|---|---|---|---|
| GET | /posts | posts | app.controllers.posts.index |
| GET | /posts/new | new_post | app.controllers.posts.new |
| GET | /posts/:id | post | app.controllers.posts.show |
| GET | /posts/:id/edit | edit_post | app.controllers.posts.edit |
| POST | /posts | posts | app.controllers.posts.create |
| PUT | /posts/:id | post | app.controllers.posts.update |
| DELETE | /posts/:id | post | app.controllers.posts.destroy |
在router.js中一行代码搞定
module.exports = (app) => {
const { router, controller, jwt } = app;
// jwt的使用,往下翻
router.resources("tags","/api/v1/tags", jwt, controller.tags); // 标签
};
model定义
定义一些标签相关字段,还可以定义校验规则,无需导入,在service层,可以通过ctx.model.Tags来访问
mongoose的使用的egg-mongoose,下面会说使用方法
app/model/tags.js
module.exports = (app) => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const TagsSchema = new Schema(
{
name: {
type: String,
min: 2,
max: 20,
match: /^[\u4e00-\u9fa5A-Za-z0-9_]{2,20}$/,
},
createTime: {
type: Date,
default: Date.now(),
},
updateTime: {
type: Date,
default: Date.now(),
},
avatar: {
type: String,
},
articleNum: {
type: "number",
default: 0,
},
status: {
type: "boolean",
default: true,
},
},
{ versionKey: false }
);
return mongoose.model("Tags", TagsSchema, "tags");
// User是指定查找的入口,随便取;UserSchema是参数;user是你数据集合表的名称
};
service的方法
// app/service/tags.js
"use strict";
const Service = require("egg").Service;
class TagsService extends Service {
// 分页查询
async index(params = {}) {
const { ctx } = this;
try {
const page = params.page * 1;
const pageSize = params.pageSize * 1;
const queryCon = params.name
? {
name: {
$regex: new RegExp(params.name, "i"),
},
}
: {};
const totalCount = await ctx.model.Tags.find(queryCon).countDocuments();
const results = await ctx.model.Tags.find(queryCon)
.sort({
updateTime: -1,
})
.skip((page - 1) * pageSize)
.limit(pageSize);
return {
data: {
page,
pageSize,
totalCount,
list: results,
},
};
} catch (error) {
return {
code: 500,
msg: JSON.stringify(error),
};
}
}
// 根据字段搜索
async find(params = {}) {
try {
const { ctx } = this;
const results = await ctx.model.Tags.find(params);
return results;
} catch (error) {
return {
code: 500,
msg: JSON.stringify(error),
};
}
}
// 创建标签
async create(params) {
try {
const { ctx } = this;
const results = await ctx.model.Tags.create(Object.assign({}, params));
return results;
} catch (error) {
return {
code: 500,
msg: JSON.stringify(error),
};
}
}
// 更新标签
async update(params) {
const { ctx } = this;
try {
const results = await ctx.model.Tags.updateOne(
{
_id: params._id,
},
Object.assign({}, params)
);
return results;
} catch (error) {
return {
code: 500,
msg: JSON.stringify(error),
};
}
}
// 删除标签
async destroy(params) {
const { ctx } = this;
try {
const results = await ctx.model.Tags.deleteOne({
_id: params.id,
});
return results;
} catch (err) {
return {
code: 500,
msg: JSON.stringify(err),
};
}
}
}
module.exports = TagsService;
controller层方法
实现增删查改的一套方法,访问名字遵循RESTful风格约定的方法
// app/controller/tags.js
"use strict";
const Controller = require("egg").Controller;
class TagsController extends Controller {
get createRule() {
return {
name: {
type: "string",
min: 2,
max: 20,
match: /^[\u4e00-\u9fa5A-Za-z0-9_]{2,20}$/,
},
};
}
// 条件查询
async index() {
const { ctx } = this;
const { pageSize = 10, page = 1, name = "" } = ctx.query || {};
const res = await ctx.service.tags.index({ page, pageSize, name });
if (res.code === 500) {
return ctx.helper.error(res);
}
ctx.helper.success({ res });
}
// /tags/:id 查询
async show() {
const { ctx } = this;
const { pageSize = 10, page = 1, name = "" } = ctx.query || {};
const res = await ctx.service.tags.index({ page, pageSize, name });
if (res.code === 500) {
return ctx.helper.error(res);
}
ctx.helper.success({ res });
}
async hasTag() {
const { ctx } = this;
ctx.validate(this.createRule);
let tag = await ctx.service.tags.find({ name: ctx.request.body.name });
if (tag.length) {
ctx.helper.success({ msg: "该标签已存在" });
return true;
}
return false;
}
// 创建
async create() {
const { ctx } = this;
if (await this.hasTag()) return;
let res = await ctx.service.tags.create(ctx.request.body);
if (res.code === 500) {
return ctx.helper.error(res);
}
ctx.helper.success({ res });
}
// /tags/:id 更新
async update() {
const { ctx } = this;
if (await this.hasTag()) return;
let res = await ctx.service.tags.update({
...ctx.request.body,
updateTime: Date.now(),
_id: ctx.params.id,
});
if (res.code === 500) {
return ctx.helper.error(res);
}
ctx.helper.success({ res });
}
// 销毁
async destroy() {
const { ctx } = this;
const res = await ctx.service.tags.destroy(ctx.params);
if (res.code === 500) {
return ctx.helper.error(res);
}
ctx.helper.success({ res });
}
}
module.exports = TagsController;
账号注册与登录(jwt使用)
egg-mongoose使用
用于连接和操作mongodb数据库,这里就不再描述怎么安装Mongodb数据库,需要在本地电脑安装,可以直接网上查找。一般安装完的数据库默认地址都是mongodb://127.0.0.1:27017
安装egg-mongoose
npm i egg-mongoose egg-jwt
在plugin中配置
// config/plugin.js
"use strict";
module.exports = {
mongoose: {
enable: true,
package: "egg-mongoose",
},
jwt: {
enable: true,
package: "egg-jwt",
}
};
// config/config.default.js
"use strict";
module.exports = (appInfo) => {
const config = (exports = {});
// 连接数据数据库
config.mongoose = {
client: {
url: "mongodb://127.0.0.1:27017/test", // test表示数据库名称
options: {
useNewUrlParser: true,
},
},
};
config.jwt = {
secret: "admin"
};
return {
...config
};
};
在model中定义用户的数据模型
app/model/user.js
定义字段的名字和类型,用户注册登陆
module.exports = (app) => {
const mongoose = app.mongoose; // 使用的插件可以通过app直接访问
const Schema = mongoose.Schema;
const UserSchema = new Schema(
{
username: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
avatar: {
type: String,
},
date: {
type: Date,
default: Date.now(),
},
name: {
type: String,
required: true,
},
},
{ versionKey: false }
);
return mongoose.model("User", UserSchema, "user");
// User是指定查找的入口;UserSchema是参数;user是你数据集合表的名称
};
查找用户和注册用户
app/service/user.js 在service定义查找和新增用户的方法
"use strict";
const Service = require("egg").Service;
class UserService extends Service {
// 根据邮箱查找用户
async find(params) {
const { ctx } = this;
try {
const results = await ctx.model.User.findOne({ email: params.email });
return results;
} catch (err) {
return {
code: 500,
msg: JSON.stringify(err),
};
}
}
// 注册用户
async create(params) {
const { ctx } = this;
try {
const results = await ctx.model.User.create(Object.assign({}, params));
return results;
} catch (err) {
return {
code: 500,
msg: JSON.stringify(err),
};
}
}
}
module.exports = UserService;
实现注册和登录
app/controller/user.js
设置controller层的方法,路由匹配之后,执行对应的方法
"use strict";
const Controller = require("egg").Controller;
const utility = require("utility");
class UserController extends Controller {
// 注册
async register() {
const { ctx } = this;
const body = Object.assign({}, ctx.request.body);
// 1.调用查找服务,查询邮箱是否被注册
let user = await ctx.service.user.find(body);
if (user && user.email) {
ctx.body = {
code: 0,
data: null,
msg: "邮箱已被注册"
}
return;
}
body.password = utility.md5(body.password);
// 2.邮箱不存在的话,注册账号
const res = await ctx.service.user.create(body);
ctx.body = {
code: 0,
data: res,
msg: "注册成功"
};
}
// jwt登录,返回token
async login() {
const { ctx, app } = this;
const body = Object.assign({}, ctx.request.body);
// 1.根据邮箱,查找账号是否存在
let user = await ctx.service.user.find(body);
if (user && user.password === utility.md5(body.password)) {
// 2.密码正确,将通过jwt插件生成token,返回给前端
const token = app.jwt.sign(
{ username: body.username },
app.config.jwt.secret,
{
expiresIn: "1h",
}
);
ctx.body = {
code: 0,
data: {
token,
username: body.username
}
msg: "登录成功"
}
return;
}
ctx.body = {
code: 0,
data: null,
msg: "邮箱或密码错误"
}
}
}
module.exports = UserController;
配置路由
app/router.js 路由设置controller层对应的方法
"use strict";
module.exports = (app) => {
const { router, controller } = app;
router.post("/register", controller.user.register);
router.post("/login", controller.user.login);
router.get("/hello", jwt, controller.home.index);
};
使用jwt
在router中的,传入的路径参数和传入控制层方法参数之间,传入的参数都会被作为中间件使用
下面使用了jwt,会在请求头中校验token
"use strict";
module.exports = (app) => {
const { router, controller, jwt } = app;
router.get("/hello", jwt, controller.home.index);
};
接口返回401
传入token
添加请求头,值是Bearer空格后面拼接登录返回的token
Authorization: Bearer ${token}
总结
egg+mongodb实现一套小型项目的后台接口是完全没问题,大大的提升了我们的效率。Egg 奉行约定优于配置,按照一套统一的约定进行应用开发。所以减少了很多重复导入工作,开发只需专注代码逻辑。
最后
这篇文章只是一个初级的使用,参考的网上一些资料视频和官网做的一个小的demo,如果有进阶的用法或者项目,大家可以在评论区留言,欢迎大家点赞,周末愉快~