框架:egg 、umi、antd,mongodb;
mongodb安装教程
egg安装
umi: yarn create @umijs/umi-app;yarn install;yarn start;umi bulid;
初步步骤就完成了
egg
- 安装相应的插件;
→config/plugin.js
// 跨域
cors: {
enable: true,
package: 'egg-cors',
},
// mongodb 数据库
mongoose: {
enable: true, // 开启插件
package: 'egg-mongoose',
},
// 鉴权
jwt: {
enable: true,
package: 'egg-jwt',
},
- 配置
→config/config.default.js
config.security = {
csrf: {
enable: false,
ignoreJSON: true,
},
// domainWhiteList: [ '*' ], // []中放放出的白名单,*代表所有
};
// 白名单 domainWhiteList: ['127.0.0.1:8080']
// 配置跨域 config.cors = { origin: 'http:127.0.0.1:8080'
// 匹配规则 域名+端口 *则为全匹配 allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH', credentials: true };
config.cors = {
origin: '*',
allowMethods: 'GET,HEAD,PUT,OPTIONS,POST,DELETE,PATCH',
credentials: true,
};
// 配置访问地址
config.cluster = {
listen: {
path: '',
port: 3000,
hostname: '192.168.1.1', // ip地址
},
};
// config中配置mongoose连接mongodb数据库
// Mongodb://eggadmin:123456@localhost:27017 //有用户名密码的情况
// user 数据库名称
config.mongoose = {
client: {
url: 'mongodb://127.0.0.1:27017/user',
options: {
useNewUrlParser: true,
},
},
};
// 鉴权 生成token
config.jwt = {
secret: '123456', // 自定义token的加密条件字符串,可按各自的需求填写
ignore: ['/api/registered', '/api/login'], // 哪些请求不需要认证
// enable: true, // default is false
// match: '/jwt', // optional
expiresIn: '24h',
};
- 创建数据模型 →app/model/user.js
'use strict';
module.exports = app => {
const mongoose = app.mongoose;
// 定义数据库的结构
const Schema = mongoose.Schema;
// 按照mock的数据,字段:name/password id自动生成
const UserSchema = new Schema({
// _id: {
// type: Number,
// },
username: {
type: String,
},
password: {
type: String,
},
lastTime: {
type: Number,
},
token: {
type: String,
},
role: {
type: String,
},
dsc: {
type: String,
},
});
// 映射到egg-mongo db 库的user表中(不区分大小写)
const User = mongoose.model('users', UserSchema);
// 方法放到这里
initUserData(User);
return User;
};
// Entity 可以绑定具体数据对Model实例化
function initUserData(User) {
// 查询数据库
User.find({}, (err, doc) => {
if (err) {
console.log(err);
console.log('创建用户失败');
} else if (!doc.length) {
new User({
username: 'admin',
password: '123456',
role: 'admin',
dsc: '拥有系统内所有菜单和路由权限',
lastTime: Date.now(),
}).save();
} else {
console.log('-------------创建用户成功--------------');
}
});
}
先打开navicat连接数据库 检查是否连接上,运行项目后会发现自动创建数据表,打开表有数据说明添加成功了;
4. 注册
控制器:app/controller/user.js
'use strict';
/** 控制器 */
const Controller = require('egg').Controller;
class IndexController extends Controller {
/** 注册 */
* registered() {
const params = yield this.ctx.request.body;
yield this.ctx.service.user.registered(params);
}
}
module.exports = IndexController;
服务器: 主要用来做逻辑判断,app/service/user.js
'use strict';
const Service = require('egg').Service;
class IndexService extends Service {
// 注册
* registered(params) {
// 注册判断是否存在
const corr = yield this.ctx.model.User.findOne({ username: params.username });
params.role = 'user';
if (!corr) {
yield this.ctx.model.User.insertMany([ params ]);
this.ctx.body = '注册成功';
} else {
this.ctx.body = '该用户名已注册';
}
}
}
module.exports = IndexService;
- 路由 app/router.js
'use strict';
module.exports = app => {
const { router, controller, jwt } = app; // jwt 后续会用到做token验证
router.post('/api/registered', controller.user.registered); // 注册
};
添加用户成功
登录
- 控制器:app/controller/user.js
/** 登录 */
* login() {
const params = yield this.ctx.request.body;
yield this.ctx.service.user.login(params);
}
- app/service/user.js
// 登录
* login(params) {
const { ctx, app } = this;
const corr = yield ctx.model.User.findOne({ username: params.username });
// 用户是否存在
if (!corr) {
this.ctx.body = '用户名错误';
} else {
if (params.password === corr.password) {
// 生成Token
const Token = app.jwt.sign({
username: params.username, // 需要存储的Token数据
}, app.config.jwt.secret, {
expiresIn: '1800s', // 有效期时间
});
// token 存储至数据库中
yield ctx.model.User.updateOne({ username: params.username }, { token: Token }, { multi: true });
const user = yield ctx.model.User.findOne({ username: params.username });
// 将生成的Token返回给前端
ctx.body = user;
} else {
this.ctx.body = '密码错误,请重新输入!';
}
}
}
- 路由 app/router.js
'use strict';
module.exports = app => {
const { router, controller, jwt } = app; // jwt 后续会用到做token验证
router.post('/api/registered', controller.user.registered); // 注册
router.post('/api/login', controller.user.login); // 登录并生成Token
};
antd
code:
models/user.ts
import { Effect, Reducer } from 'umi';
import { setToken } from '@/utils/localToken';
import { ResponseData } from '@/pages/data';
import { accountLogin, accountRegistered } from '@/services/user';
/**
* 用户state状态
*/
export interface CurrentUser {
_id: number;
username: string;
roles: string[];
}
export interface UserModelState {
currentUser: CurrentUser;
message: number;
loginStatus: string
}
export interface ModelType {
namespace: string;
state: UserModelState;
effects: {
login: Effect;
register: Effect;
};
reducers: {
changeLoginStatus: Reducer<string>;
};
}
const initState: UserModelState = {
currentUser: {
_id: 0,
username: '',
roles: [],
},
message: 0,
loginStatus: 'ok',
};
const Model: ModelType = {
namespace: 'user',
state: initState,
effects: {
// 登录
*login({ payload }, { call, put }) {
let status = undefined;
try {
// 获取token
const response: ResponseData = yield call(accountLogin, payload);
const { token, role, username } = response;
// 存储本地Token
yield call(setToken, token || '');
status = 'ok';
} catch (error) {
if (error.message && error.message === 'CustomError') {
status = 'error';
}
}
yield put({ type: 'changeLoginStatus', payload: status, });
if (status === 'ok') { return true; } else if (status === 'error') { return false; }
return undefined;
},
// 注册
*register({ payload }, { call, put }) {
let status = undefined;
try {
const msg = yield call(accountRegistered, payload);
status = msg;
} catch (error) {
status = 'error';
}
if (status === 'error') { return false; }
return status;
},
},
reducers: {
changeLoginStatus(state: any, { payload }) {
return {
...initState,
...state,
loginStatus: payload,
};
},
}
};
export default Model;
pages/login/index.ts
import React, { useState } from 'react';
import { connect } from 'dva'
import { Dispatch, Link, useIntl, history, useModel } from 'umi';
import styles from './index.less';
import { UserModelState } from '@/models/user';
import { Form, Input, Button, Alert, message } from 'antd';
import { UserOutlined, UnlockOutlined } from '@ant-design/icons';
import { LoginParamsType } from '@/pages/data.d';
/**
* 登录页
*/
interface LoginProps {
userLogin: UserModelState;
submitLoading?: boolean;
dispatch: Dispatch;
location: Location & { query: any };
}
const Login: React.FC<LoginProps> = props => {
const { userLogin, submitLoading, dispatch, location } = props;
const { query } = location;
const { redirect } = query;
const { loginStatus } = userLogin;
const { formatMessage } = useIntl();
const [loginForm] = Form.useForm();
const [formName, setFormName] = useState('login');
// 登录
const handleSubmit = async (values: any) => {
if (formName === 'login') {
const res: boolean = await dispatch({
type: 'user/login',
payload: values[formName],
});
if (res === true) {
message.success('登录成功!');
history.replace(redirect || '/');
}
} else {
const res: boolean = await dispatch({
type: 'user/register',
payload: values[formName],
});
message.success(res);
}
};
// 表单组件
const FormItemComponents = (props: any) => {
const { name } = props;
return (<>
<h1 className={styles.title}>
{name === 'login' ? '账户登录' : '账户注册'}
</h1>
<Form name="basic" onFinish={handleSubmit} initialValues={{}} form={loginForm}>
<Form.Item
label=""
name={[name, "username"]}
rules={[{ required: true, message: '请输入用户名', },]}
>
<Input placeholder={'用户名: admin or test or user'} prefix={<UserOutlined />} />
</Form.Item>
<Form.Item
label=""
rules={[{ required: true, message: '请输入密码', },]}
name={[name, 'password']}
>
<Input.Password
placeholder={'密码:123456'}
prefix={<UnlockOutlined />}
/>
</Form.Item>
{
name === 'login' ? null : <Form.Item
label=""
name={[name, 'rePassword']}
dependencies={['password']}
hasFeedback
rules={[
{
required: true,
message: '请确认密码!',
},
({ getFieldValue }) => ({
validator(_, value) {
if (!value || getFieldValue([name, 'password']) === value) {
return Promise.resolve();
}
return Promise.reject(new Error('您输入的两个密码不匹配!'));
},
}),
]}
>
<Input.Password placeholder={'确认密码'} prefix={<UnlockOutlined />} />
</Form.Item>
}
<Form.Item>
<Button
type="primary"
className={styles.submit}
htmlType="submit"
loading={submitLoading}
>
{name === 'login' ? '登录' : ' 注册'}
</Button>
</Form.Item>
<div className={styles['text-align-right']} onClick={registerClickedHandler}>
{name === 'login' ? ' 还没有账户?现在注册!' : '现在就去登录!'}
</div>
{loginStatus === 'error' && !submitLoading && (
<Alert
message={'用户名或密码错误!'}
type="error"
showIcon
/>
)}
</Form>
</>
)
}
// 切换注册
const registerClickedHandler = () => {
if (formName === 'login') {
setFormName('register')
} else {
setFormName('login')
}
loginForm.resetFields();
}
return (
<div className={styles.main}>
<FormItemComponents name={formName} />
</div>
);
};
export default connect(({ user, loading }: {
user: UserModelState; loading: {
effects: {
[key: string]: boolean;
};
}
}) => ({
userLogin: user,
submitLoading: loading.effects['userLogin/login'],
}))(Login);