第一篇、搭建前(vue)后(node)端环境,开发一个简单的登录功能
一、环境准备
- 操作系统:支持 macOS,Linux,Windows
- 运行环境:建议选择 LTS 版本,最低要求 8.x。
二、快速初始化服务端eggjs项目
Egg.js 为企业级框架和应用而生,我们希望由 Egg.js 孕育出更多上层框架,帮助开发团队和开发人员降低开发和维护成本。
注:Egg.js 缩写为 Egg
设计原则
我们深知企业级应用在追求规范和共建的同时,还需要考虑如何平衡不同团队之间的差异,求同存异。所以我们没有选择社区常见框架的大集市模式(集成如数据库、模板引擎、前端框架等功能),而是专注于提供 Web 开发的核心功能和一套灵活可扩展的插件机制。我们不会做出技术选型,因为固定的技术选型会使框架的扩展性变差,无法满足各种定制需求。通过 Egg,团队的架构师和技术负责人可以非常容易地基于自身的技术架构在 Egg 基础上扩展出适合自身业务场景的框架。
Egg 的插件机制有很高的可扩展性,一个插件只做一件事(比如 Nunjucks 模板封装成了 egg-view-nunjucks、MySQL 数据库封装成了 egg-mysql)。Egg 通过框架聚合这些插件,并根据自己的业务场景定制配置,这样应用的开发成本就变得很低。
Egg 奉行『约定优于配置』,按照一套统一的约定进行应用开发,团队内部采用这种方式可以减少开发人员的学习成本,开发人员不再是『钉子』,可以流动起来。没有约定的团队,沟通成本是非常高的,比如有人会按目录分栈而其他人按目录分功能,开发者认知不一致很容易犯错。但约定不等于扩展性差,相反 Egg 有很高的扩展性,可以按照团队的约定定制框架。使用 Loader 可以让框架根据不同环境定义默认配置,还可以覆盖 Egg 的默认约定。
与社区框架的差异
Express 是 Node.js 社区广泛使用的框架,简单且扩展性强,非常适合做个人项目。但框架本身缺少约定,标准的 MVC 模型会有各种千奇百怪的写法。Egg 按照约定进行开发,奉行『约定优于配置』,团队协作成本低。
Sails 是和 Egg 一样奉行『约定优于配置』的框架,扩展性也非常好。但是相比 Egg,Sails 支持 Blueprint REST API、WaterLine 这样可扩展的 ORM、前端集成、WebSocket 等,但这些功能都是由 Sails 提供的。而 Egg 不直接提供功能,只是集成各种功能插件,比如实现 egg-blueprint,egg-waterline 等这样的插件,再使用 sails-egg 框架整合这些插件就可以替代 Sails 了。
特性
安装
推荐直接使用脚手架,只需几条简单指令,即可快速生成项目(npm >=6.1.0):
$ mkdir egg-example && cd egg-example
$ npm init egg --type=simple
$ npm i
得到目录结构如下:
egg-project
├── package.json
├── app.js (可选)
├── agent.js (可选)
├── app
| ├── router.js
│ ├── controller
│ | └── home.js
│ ├── service (可选)
│ | └── user.js
│ ├── middleware (可选)
│ | └── response_time.js
│ ├── schedule (可选)
│ | └── my_task.js
│ ├── public (可选)
│ | └── reset.css
│ ├── view (可选)
│ | └── home.tpl
│ └── extend (可选)
│ ├── helper.js (可选)
│ ├── request.js (可选)
│ ├── response.js (可选)
│ ├── context.js (可选)
│ ├── application.js (可选)
│ └── agent.js (可选)
├── config
| ├── plugin.js
| ├── config.default.js
│ ├── config.prod.js
| ├── config.test.js (可选)
| ├── config.local.js (可选)
| └── config.unittest.js (可选)
└── test
├── middleware
| └── response_time.test.js
└── controller
└── home.test.js
启动项目:
$ npm run dev
$ open http://localhost:7001
三、建立一个会员信息表,mysql>=5.7
建立一个会员信息表,有用户名密码等信息
四、使用egg-mysql插件访问数据库
egg框架提供了 egg-mysql 插件来访问 MySQL 数据库。这个插件既可以访问普通的 MySQL 数据库,也可以访问基于 MySQL 协议的在线数据库服务。
安装与配置
安装对应的插件 egg-mysql :
$ npm i --save egg-mysql
开启插件:
// config/plugin.js
exports.mysql = {
enable: true,
package: 'egg-mysql',
};
在 config/config.${env}.js
配置各个环境的数据库连接信息。
单数据源
如果我们的应用只需要访问一个 MySQL 数据库实例,可以如下配置:
// config/config.${env}.js
exports.mysql = {
// 单数据库信息配置
client: {
// host
host: 'mysql.com',//本机127.0.0.1
// 端口号
port: '3306',
// 用户名
user: 'test_user',
// 密码
password: 'test_password',
// 数据库名
database: 'users',//users
},
// 是否加载到 app 上,默认开启
app: true,
// 是否加载到 agent 上,默认关闭
agent: false,
};
使用方式:
await app.mysql.query(sql, values); // 单实例可以直接通过 app.mysql 访问
多数据源
如果我们的应用需要访问多个 MySQL 数据源,可以按照如下配置:
exports.mysql = {
clients: {
// clientId, 获取client实例,需要通过 app.mysql.get('clientId') 获取
db1: {
// host
host: 'mysql.com',
// 端口号
port: '3306',
// 用户名
user: 'test_user',
// 密码
password: 'test_password',
// 数据库名
database: 'test',
},
db2: {
// host
host: 'mysql2.com',
// 端口号
port: '3307',
// 用户名
user: 'test_user',
// 密码
password: 'test_password',
// 数据库名
database: 'test',
},
// ...
},
// 所有数据库配置的默认值
default: {
},
// 是否加载到 app 上,默认开启
app: true,
// 是否加载到 agent 上,默认关闭
agent: false,
};
使用方式:
const client1 = app.mysql.get('db1');
await client1.query(sql, values);
const client2 = app.mysql.get('db2');
await client2.query(sql, values);
在数据库里建一个users表
service层
-
在app目录下新建service目录,用来放置service层的代码
-
新建一个users.js文件
'use strict';
const Service = require('egg').Service;
class UsersService extends Service {
async account(name, pwd) {
const result = await this.app.mysql.select('users', { // 搜索 users 表
where: { name: name, password: pwd }, // WHERE 条件
});
return result;
}
}
module.exports = UsersService;
controller层
- 在controller目录下新建account.js
'use strict';
const Controller = require('../core/base_controller');
class AccontController extends Controller {
async account() {
const { ctx } = this;
//解析post请求的参数
const name = ctx.request.body.loginname;
const pwd = ctx.request.body.password;
let res = await ctx.service.users.account(name,pwd);//调用service层的方法
this.success(res);
}
}
module.exports = AccontController;
- 这里base_controller是自己创建的一个基类controller,在app目录下新建“/core/base_controller.js”。
const { Controller } = require('egg');
class BaseController extends Controller {
success(data) {
this.ctx.body = {
success: true,
data,
};
}
notFound(msg) {
msg = msg || 'not found';
this.ctx.throw(404, msg);
}
}
module.exports = BaseController;
- 配置服务端路由
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
router.get('/', controller.home.index);
router.post('/account', controller.accont.account);//我们的简单登录验证接受post请求
// controller.accont.account 是accountController里的account方法,,,accont拼写错了
};
这样我们简单的一个服务端就写好了。
五、初始化一个前端vue项目
- 安装一下vue的clivue-cli,初始化一个vue工程
npm install -g @vue/cli-service-global
vue ui //用图形化界面创建vue工程
六、引用element-ui 插件
自己配一个喜欢的主题色,我自己瞎配了个绿色。
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import './plugins/element.js'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
七、封装请求模块
安装axios
在src目录下新建“http/http.js”,在这里我们先初步简单封装一下我们前端的请求模块:
import axios from "axios";
axios.defaults.timeout = 5000;
axios.defaults.baseURL = 'http://127.0.0.1:7001';
// axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/json';
function get(url, data = {}) {
return new Promise((resolve, reject) => {
axios.get(url, {
params: data
}).then(response => {
resolve(response.data);
}).catch(err => {
reject(err)
})
})
}
function post(url, data = {}) {
return new Promise((resolve, reject) => {
axios.post(url, data).then(response => {
resolve(response.data);
}).catch(err => {
reject(err)
});
})
}
function patch(url, data = {}) {
return new Promise((resolve, reject) => {
axios.patch(url, data)
.then(response => {
resolve(response.data);
}, err => {
reject(err)
})
})
}
function put(url, data = {}) {
return new Promise((resolve, reject) => {
axios.put(url, data)
.then(response => {
resolve(response.data);
}, err => {
reject(err)
})
})
}
export default { get,post,patch,put }
在新建一个api.js文件用来管理一下我们前端的请求接口:
import http from "./http";
/**
* login 页面
*/
export const login = (data) => http.post("/account",data);//用户登录
八、创建登录页面,实现简单登录
在views里新建“login/login.vue”
<template>
<div>
<div style="height: 300px;margin-top: 100px">
<p style="text-align: center;"><img src="../../assets/logo.png"></p>
</div>
<div style="width: 350px;margin: 0 auto">
<el-form ref="form" :model="form">
<el-form-item label="">
<el-input v-model.trim="form.loginname" placeholder="用户名"></el-input>
</el-form-item>
<el-form-item label="">
<el-input v-model.trim="form.password" placeholder="密码"></el-input>
</el-form-item>
<el-form-item label="">
<el-button type="primary" style="width: 100%" @click="login">登录</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
import {login} from "../../http/api";
export default {
name: "loign",
data() {
return {
form: {
loginname: "",
password: ""
}
}
},
methods: {
login() {
login(this.form).then(res => {
if (res.success) {
if(res.data.length > 0){
this.$message.success("成功!页面跳转中");
this.$router.push("/conent");
}else {
this.$message.error("失败");
}
}else {
this.$message.error("失败")
}
}).catch(e => {
console.log(e)
})
}
}
}
</script>
<style scoped>
</style>
配置一下前端路由
{
path: '/',
name: 'Login',
component: Login
},
npm run serve
好啦,一个简单的登录完成了!
快来打赏我吧!