zoukankan      html  css  js  c++  java
  • egg实现登录鉴权(六):角色树的CRUD操作

    前面已经完成角色树的存储并且能够查询并构建出树形数据,本文继续完成角色树的其他操作,可以插入,删除和修改等常规操作。

    需求

    • 查询不鉴权,增删改需要传token
    • 能够通过id查询角色,返回该角色下面所有角色树。
    • 插入新角色,可以另开一个组织架构,即该角色没有上级
    • 修改角色和删除角色,修改和删除角色时要判断该角色是否存在,
    • 修改角色分两种情况
      • 修改角色名称,不改变结构
      • 修改上级id,修改该角色上级时,该角色的下级默认一并带入;
    • 删除角色时如果有下级则一并删除

    约定

    名次解释:

    id:角色id

    pid:角色上级id

    name:角色名称

    • 通过id查询角色树
      • 参数:id(可选),不传则查询所有
      • 成功返回:角色树,json格式数组
      • 失败返回:{code:400,msg:'查询失败'}
    • 新增角色
      • 参数:pid(可选),name(必选),pid为空则该角色为顶级
      • 成功返回:{code:200,msg:'新增成功'}
    • 修改角色
      • 参数:id(必选),name(可选),pid(可选)
      • 成功返回:{code:200,msg:'修改成功'}
      • 失败返回:{code:400,msg:'修改失败'}
    • 删除角色
      • 参数:id(必选)
      • 成功返回:{code:200,msg:'删除成功'}
      • 失败返回:{code:400,msg:'删除失败'}

    实现

    注意力转移到角色表,user表和config都和之前一样,没有改动。难点在同个id查询角色树和删除角色时要同时删除子集

    • 数据库,用户名:root,密码:123456,表:test
    • image.png
    • 目录结构
    • image.png
    • app/model/role.js
    'use strict';
    
    module.exports = app => {
      const { INTEGER, STRING } = app.Sequelize;
      const Role = app.model.define('role', {
        id: { type: INTEGER, primaryKey: true, autoIncrement: true },
        name: STRING(50),
        pid: INTEGER,
      }, {
        timestamps: false,
      });
      return Role;
    };
    • app/controller/role.js
    'use strict';
    
    const Controller = require('egg').Controller;
    
    class RoleController extends Controller {
      async index() {
        const { ctx } = this;
        ctx.body = await ctx.service.role.getRole();
      }
      async show() {
        const { ctx } = this;
        ctx.body = await ctx.service.role.getRole(ctx.params.id);
      }
      // 插入角色
      async create() {
        const { ctx } = this;
        const { name, pid } = ctx.request.body;
        await ctx.service.role.addRole(name, pid);
        ctx.body = { code: 200, msg: '新增成功' };
      }
      // 更新角色
      async update() {
        const { ctx } = this;
        const { name, pid } = ctx.request.body;
        await ctx.service.role.editRole(ctx.params.id, name, pid);
        if (ctx.status === 404) {
          ctx.body = { code: 400, msg: '修改失败' };
        } else {
          ctx.body = { code: 200, msg: '修改成功' };
        }
      }
      // 移除角色
      async remove() {
        const { ctx } = this;
        await ctx.service.role.removeRole(ctx.params.id);
        if (ctx.status === 404) {
          ctx.body = { code: 400, msg: '删除失败' };
        } else {
          ctx.body = { code: 200, msg: '删除成功' };
        }
      }
    }
    module.exports = RoleController;
    • app/service/role.js(重点)
    'use strict';
    const Service = require('egg').Service;
    function toInt(str) {
      if (typeof str === 'number') return str;
      if (!str) return str;
      return parseInt(str, 10) || 0;
    }
    class RoleService extends Service {
      // 构建树形结构数据
      // 如果id为空,则构建所有的数据
      // id不为空,则构建以id为根结点的树
      buildTree(id, data) {
        const res = [];
        if (id) {
          for (const item of data) {
            if (toInt(item.id) === toInt(id)) {
              item.children = getNode(id);
              res.push(item);
            }
          }
        } else {
          for (const item of data) {
            if (!item.pid) {
              item.children = getNode(item.id);
              res.push(item);
            }
          }
        }
        // 传入根结点id 递归查找所有子节点
        function getNode(id) {
          const node = [];
          for (const item of data) {
            if (toInt(item.pid) === toInt(id)) {
              item.children = getNode(item.id);
              node.push(item);
            }
          }
          if (node.length === 0) return;
          return node;
        }
        return res;
      }
      // 获取所有子节点集合
      getChildrenIds(treeData) {
        const res = [];
        function getIds(treeData, res) {
          for (const item of treeData) {
            res.push(item.id);
            if (item.children) { getIds(item.children, res); }
          }
        }
        getIds(treeData, res);
        return res;
      }
      // 查询角色并构建角色树
      async getRole(id) {
        const { ctx } = this;
        const query = { limit: toInt(ctx.query.limit), offset: toInt(ctx.query.offset) };
        const data = await ctx.model.Role.findAll({ query, raw: true });
        return this.buildTree(id, data);
      }
      // 根据id查询角色
      async getRoleById(id) {
        const { ctx } = this;
        return await ctx.model.Role.findByPk(toInt(id));
      }
      // 插入角色
      async addRole(name, pid) {
        const { ctx } = this;
        await ctx.model.Role.create({ name, pid });
      }
      // 修改角色
      async editRole(id, name, pid) {
        const { ctx } = this;
        const role = await this.getRoleById(toInt(id));
        if (!role) {
          ctx.status = 404;
          return;
        }
        await role.update({ name: name || role.name, pid: pid || role.pid });
        ctx.status = 200;
      }
      // 删除角色
      async removeRole(id) {
        const { ctx } = this;
        const roleTree = await this.getRole(toInt(id));
        const role = await this.getRoleById(toInt(id));
        if (!role) {
          ctx.status = 404;
          return;
        }
        const ids = this.getChildrenIds(roleTree);
        for (const i of ids) {
          const r = await this.getRoleById(toInt(i));
          r.destroy();
        }
        ctx.status = 200;
      }
    }
    module.exports = RoleService;
     
    • app/router.js(角色路由,user相关暂时可不管)
    'use strict';
    
    /**
     * @param {Egg.Application} app - egg application
     */
    module.exports = app => {
      const { router, controller, jwt } = app;
      router.get('/', controller.home.index);
    
      router.post('/user/login', controller.user.login);
      // 查询用户
      router.get('/user', controller.user.index);
      router.get('/user/:id', jwt, controller.user.show);
      // 新增
      router.put('/user', jwt, controller.user.create);
      // 修改密码
      router.post('/user/:id', jwt, controller.user.updatePwd);
    
    
      // 获取角色
      router.get('/role', controller.role.index);
      router.get('/role/:id', jwt, controller.role.show);
      // 插入角色
      router.put('/role', jwt, controller.role.create);
      // 修改角色
      router.post('/role/:id', jwt, controller.role.update);
      // 删除角色
      router.delete('/role/:id', jwt, controller.role.remove);
    };
    • package.json
    {
      "name": "jwt",
      "version": "1.0.0",
      "description": "",
      "private": true,
      "egg": {
        "declarations": true
      },
      "dependencies": {
        "egg": "^2.15.1",
        "egg-cors": "^2.2.3",
        "egg-jwt": "^3.1.7",
        "egg-scripts": "^2.11.0",
        "egg-sequelize": "^5.2.0",
        "mysql2": "^2.0.2"
      },
      "devDependencies": {
        "autod": "^3.0.1",
        "autod-egg": "^1.1.0",
        "egg-bin": "^4.11.0",
        "egg-ci": "^1.11.0",
        "egg-mock": "^3.21.0",
        "eslint": "^5.13.0",
        "eslint-config-egg": "^7.1.0"
      },
      "engines": {
        "node": ">=10.0.0"
      },
      "scripts": {
        "start": "egg-scripts start --daemon --title=egg-server-jwt",
        "stop": "egg-scripts stop --title=egg-server-jwt",
        "dev": "egg-bin dev",
        "debug": "egg-bin debug",
        "test": "npm run lint -- --fix && npm run test-local",
        "test-local": "egg-bin test",
        "cov": "egg-bin cov",
        "lint": "eslint .",
        "ci": "npm run lint && npm run cov",
        "autod": "autod"
      },
      "ci": {
        "version": "10"
      },
      "repository": {
        "type": "git",
        "url": ""
      },
      "author": "",
      "license": "MIT"
    }

    测试

    • 通过id查询角色

    image.png

    • 查询所有角色

    image.png

    • 插入角色

    image.png

    • 修改角色,

    image.png

    • 删除角色

    image.png

    总结

    • 通过id获取子节点
    • 遍历树形json获取所有子节点id集合
    • 循环遍历ids,删除当前节点的所有子节点
  • 相关阅读:
    JAVA8 之 Stream 流(四)
    关于iphone 6s 页面功能不能正常使用问题
    关于ES6语法的 一些新的特性
    微信授权一直跳转
    js 一道题目引发的正则的学习
    关于this在不同使用情况表示的含义
    详细解析arry.map() ,function.apply() 方法
    关于服务器无法在已发送http表头之后设置状态问题
    七牛上传视频并转码
    使用 v-cloak 防止页面加载时出现 vuejs 的变量名
  • 原文地址:https://www.cnblogs.com/xingguozhiming/p/12157019.html
Copyright © 2011-2022 走看看