通用CRUD接口
server端创建查找模块中间件
server/middleware/resource.js
module.exports = options => {
return async (req, res, next) => {
const modelName = req.params.resource
req.Model = require(`../models/${modelName}`)
console.log('modelName',modelName)
next()
}
}
model/user-admin.js 建数据模型
const mongoose = require('mongoose')
const schema = new mongoose.Schema({
username:{
type:String,
required: true,
},
role:{
type:String,
required: true,
},
password:{
type:String,
select:false,//防止查询出密码
set(val) { //密码加密存储
return require('bcrypt').hashSync(val, 10)
}
},
})
module.exports = mongoose.model('user-admin',schema)
route/admin/index.js 接口文件引入
//合并URL参数,将父级的参数合并到router里面
const router = express.Router({
mergeParams: true
})
// 通用件接口改造
// 创建资源
router.post('/', async (req, res) => {
const model = await req.Model.create(req.body)
res.send(model)
})
// 更新资源
router.put('/:id', async (req, res) => {
const model = await req.Model.findByIdAndUpdate(req.params.id, req.body)
res.send(model)
})
// 删除资源
router.delete('/:id', async (req, res) => {
await req.Model.findByIdAndDelete(req.params.id)
res.send({
success: true
})
})
// 资源列表 - 分页
router.get('/', async (req, res) => {
const queryOptions = {}
if (req.Model.modelName === 'route') {
queryOptions.populate = 'parentId'
}
const items = await req.Model.find().setOptions(queryOptions).limit(100)
console.log('items',items)
res.send(items)
})
// 资源详情
router.get('/:id', async (req, res) => {
const model = await req.Model.findById(req.params.id)
console.log('model',model)
res.send(model)
})
// 调用通用接口中间件
const resourceMiddleware = require('../../middleware/resource')
app.use('/admin/api/rest/:resource', resourceMiddleware(), router)
// 路径,中间件,回调函数
// 统一异常处理
app.use( async (err,req,res,next) => {
res.status(err.statusCode || 500).send({
message: err.message
})
})
admin前端新增用户编辑页面
......html....
接口调用带rest前缀=>后端通用校验
async save(){
let res
if (this.id) {
res = await this.$http.put(`/rest/user-admin/${this.id}`, this.userForm)
} else {
res = await this.$http.post('/rest/user-admin', this.userForm)
}
console.log('res',res)
this.$router.push('/user/list')
this.$message({
type: 'success',
message: '保存成功'
})
},
async fetch(){
const res = await this.$http.get(`/rest/user-admin/${this.id}`)
this.model = res.data
},
路由文件router/index.js 添加路径 ,路由文件挂在main.js中
import Main from '../views/Main'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Main',
component: Main,
meta: { title:'系统管理' },
children:[
{
path:'/route',
meta: { title:'系统管理' },
component: () => import('@/views/route')
},
{
path:'/user/list',
meta: { title:'用户管理' },
component: () => import('@/views/user/List')
},
{
path:'/user/edit',
meta: { title:'用户编辑' },
component: () => import('@/views/user/Edit')
}
]
},
]
const router = new VueRouter({
base: process.env.BASE_URL,
routes
})
export default router
登录实现 - 先添加一个用户再加登录token!!!!
server端添加登录校验中间件auth.js
module.exports = options => {
// 断言库 if false => ()
const assert = require('http-assert')
const config =require('../config')
const jwt = require('jsonwebtoken')
/*const userAdmin = require('../models/user-admin')*/
return async (req, res, next) => {
const token = String(req.headers.authorization || '').split(' ').pop()
// token 为false =》 401 提示
assert(token, 401, '请先登录')
const { id } = jwt.verify(token, config.secretKey)
// id 为false =》 401 提示
assert(id, 401, '请先登录')
await next()
}
}
router/admin/index.js 应用,加登录接口
const assert = require('http-assert')
const jwt = require('jsonwebtoken')
// 登录调用modelB不走通用
const userAdmin = require('../../models/user-admin')
// token 校验中间件
const authMiddleware =require('../../middleware/auth')
app.use('/admin/api/rest/:resource', authMiddleware(),resourceMiddleware(), router)
// 路径,中间件,回调函数
// 登录接口
app.post('/admin/api/login', async (req, res) => {
// 结构赋值
const { username, password } = req.body
// 1.根据用户名找用户,引入模型,定义方法
const user = await userAdmin.findOne({ username
}).select('+password').select('+role')
assert(user ,422,'该用户不存在')
// 2.校验密码
// 比较密码,返回布尔值.数据表密码设置select为false不可读取,此时需要强制取出密码 findOne.select('+item')
const isValid = require('bcryptjs').compareSync(password, user.password)
assert(isValid ,422,'密码错误')
// 3.返回token,如果是错误,则在http.js中拦截器统一处理
// 设置secretOrPrivateKey !!!!!
const config =require('../../config')
const token = jwt.sign({ id: user.id },config.secretKey, {expiresIn: 1800000})
res.send({ code: 20000, message: 'ok', data: { token:token,username:username,role:user.role } })
})
config.js -> 根目录建,变量配置
module.exports = {
secretKey: 'fys-NO-ONE',
mongoUrl: 'mongodb://localhost:27017/fys-project'
}
admin前端修改
路由文件添加拦截
router.beforeEach((to, from ,next) => {
if (!to.meta.isPublic && !localStorage.token) {
return next('/login')
}
next()
})
请求拦截改造
// 请求拦截配置
http.interceptors.request.use(function (config) {
// token识别
console.log('localStorage.token',localStorage.token)
if (localStorage.token) {
config.headers.Authorization = 'Bearer ' + localStorage.token
}
return config;
}, function (error) {
return Promise.reject(error);
})
// 响应
http.interceptors.response.use(res => {
return res.data
}, err => {
if (err.response.data.message) {
Vue.prototype.$message({
type: 'error',
message: err.response.data.message
})
if (err.response.status === 401) {
router.push('/Login')
}
}
return Promise.reject(err)
})
登录.vue 调用
async login() {
const res = await this.$http.post('login', this.loginForm)
console.log('res',res)
localStorage.token = res.data.token
localStorage.username = res.data.username
localStorage.role = res.data.role
this.$router.push('/')
this.$message({
type: 'success',
message: '登录成功'
})
},