由于字数限制,请阅读原文,原文附源码和sql以及项目演示地址和项目资料。

环境:

win10、idea22023.2、vscode1.7、maven3.5、jdk8、Redis

技术:

  • springboot2.5.9

  • springsecurity

  • Redis

  • mybatis plus

  • mysql5.7.38

  • swagger

  • jwt

  • vue2

  • element ui

  • vuex

  • vue-router

  • axios

  • mockjs

  • echarts

  • less

模块:

  1. 登录页面

  2. 首页

  3. 权限管理

    1.用户管理

    2.角色管理

    3.菜单管理

功能要点:

  1. 从0到1实现项目前后端搭建

  2. vuex实现面包屑和Tag功能

  3. vuex+localStorage动态路由和菜单(重点)

  4. 封装一个ECharts组件

  5. 封装Table表格

  6. 树形表格和CheckBox的使用

  7. 封装统一返回类

  8. 两种方式实现代码生成,解放双手

  9. jwt、swagger、Redis封装

  10. 权限管理(重点)

项目截图

1、登录页面

d906325f5d7942401a06d8708517e85a.png

2、首页

3210e95481c9812f41fa647b07c48555.png

3、用户管理

c8f8ec1c6c509c9b4853818304530bea.png

4、角色管理

cc103c9863b97a10a64cf8f17cf4fb60.png

5、分配权限

34958a307f40a99bbcb655337eacdcc0.png

6、菜单管理

3d2ce369feeba22966c3a26d5747871d.png

7、根据权限动态加载菜单和按钮

e631043bc330c156d8fbc681c0a6455f.png

8、部分主要代码

登录

<template>
  <el-form
    ref="form"
    label-width="70px"
    :inline="true"
    class="login-container"
    :model="form"
    :rules="rules"
  >
    <h3 class="login_title">系统登录</h3>
    <el-form-item label="用户名" prop="username">
      <el-input v-model="form.username" placeholder="请输入账号"></el-input>
    </el-form-item>
    <el-form-item label="密码" prop="password">
      <el-input
        type="password"
        v-model="form.password"
        placeholder="请输入密码"
      ></el-input>
    </el-form-item>
    <el-form-item label="验证码" prop="code">
      <el-input v-model="form.code" maxlength="6"></el-input>
    </el-form-item>
    <el-form-item>
      <el-image
        :src="captchaImg"
        class="captchaImg"
        style="margin-left: 15px"
        @click="getCaptcha"
      ></el-image>
    </el-form-item>
    <el-form-item>
      <el-button
        @click="submit"
        style="margin-left: 105px; margin-top: 10px"
        type="primary"
        :loading="loading"
        >登录</el-button
      >
      <!-- <el-button
        @click="submit1"
        style="margin-left: 105px; margin-top: 10px"
        type="primary"
        :loading="loading"
        >登录1</el-button
      > -->
    </el-form-item>
  </el-form>
</template>
<script>
// import Mock from 'mockjs'
// import Cookie from 'js-cookie'
// import { getMenu } from '../api'
import qs from "qs";
import http from "@/utils/request";
export default {
  data() {
    return {
      captchaImg: "",
      loading: false,
      form: {
        username: "admin",
        password: "111111",
        token: "aaaaa",
        code: "",
      },
      rules: {
        username: [
          { required: true, trigger: "blur", message: "请输入用户名" },
        ],
        password: [{ required: true, trigger: "blur", message: "请输入密码" }],
      },
    };
  },


  created() {
    this.getCaptcha();
  },
  methods: {
    submit1() {},
    getCaptcha() {
      http.get("/captcha").then((res) => {
        if(res.code === 20000){
          console.log("/captcha");
          console.log(res);
          this.form.token = res.data.data.token;
          this.captchaImg = res.data.data.captchaImg;
          //this.form.code = "";
        }


      });
    },
    // 登录
    submit() {
      let that = this;
      that.$refs.form.validate((valid) => {
        if (valid) {
          this.loading = true;
          this.$store
            .dispatch("Login", this.form)
            .then((res) => {
           
              if (res.code != 20000) {
                that.$message({
                  type: "warning",
                  message: res.message,
                });
                this.loading = false;
                return false;
              }
              this.loading = false;
              this.$router.push({ path: "/home" });
            })
            .catch(() => {
              this.loading = false;
            });
          // http
          //   .post("/login?" + qs.stringify(this.form))
          //   .then((res) => {
          //     if (res.code != 20000) {
          //       that.$message({
          //         type: "warning",
          //         message: res.message,
          //       });
          //     }
          //     console.log(res);


          //       const jwt = res.data.authorization;


          //      this.$store.commit("SET_TOKEN", jwt);
          //     //
          //     this.$router.push("/home");
          //   })
          //   .catch((e) => {});


          //this.loading = true;
          // that.$store
          //   .dispatch("Login", that.form)
          //   .then(() => {
          //     //this.loading = false;
          //     that.$router.push({ path: "/" });
          //   })
          //   .catch(() => {
          //     //this.loading = false;
          //   });
        } else {
          console.log("error submit!!");
          return false;
        }
      });


      // // token信息
      // const token = Mock.Random.guid()


      // 校验通过
      // this.$refs.form.validate((valid) => {
      //     if (valid) {
      //         getMenu(this.form).then(({ data }) => {
      //             console.log(data)
      //             if (data.code === 20000) {
      //                 // token信息存入cookie用于不同页面间的通信
      //                 Cookie.set('token', data.data.token)


      //                 // 获取菜单的数据,存入store中
      //                 this.$store.commit('setMenu', data.data.menu)
      //                 this.$store.commit('addMenu', this.$router)
      //                 // 跳转到首页
      //                 this.$router.push('/home')
      //             } else {
      //                 this.$message.error(data.data.message);
      //             }
      //         })
      //     }
      // })
    },
  },
};
</script>
<style lang="less" scoped>
.login-container {
  width: 650px;
  border: 1px solid #eaeaea;
  margin: 180px auto;
  padding: 35px 35px 15px 35px;
  background-color: #fff;
  border-radius: 15px;
  box-shadow: 0 0 25px #cac6c6;
  box-sizing: border-box;
  .login_title {
    text-align: center;
    margin-bottom: 40px;
    color: #505458;
  }
  .el-input {
    width: 198px;
  }
}
</style>

菜单

<template>
  <div>
    <el-table
      :data="tableData"
      style="width: 100%; margin-bottom: 20px"
      row-key="id"
      border
      default-expand-all
      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
    >
      <el-table-column prop="name" label="名称" sortable min-width="20%">
      </el-table-column>
      <el-table-column prop="path" label="访问路径" sortable min-width="15%">
      </el-table-column>


      <el-table-column
        prop="component"
        label="组件路径"
        sortable
        min-width="15%"
      >
      </el-table-column>
      <el-table-column
        prop="permissionValue"
        label="权限值"
        sortable
        min-width="15%"
      >
      </el-table-column>
      <el-table-column prop="status" label="状态" sortable min-width="10%">
      </el-table-column>
      <el-table-column prop="icon" label="图标" sortable min-width="10%">
      </el-table-column>


      <el-table-column label="操作" min-width="15%">
        <template slot-scope="scope">
          <!-- 第一层和第二层可以添加菜单,第三层添加功能,第四层修改功能 -->
          <el-button
            v-if="scope.row.level === 1 || scope.row.level === 2"
            type="text"
            size="mini"
            @click="addOrEditMenuDialog(scope.row, 'add')"
            >添加菜单</el-button
          >
          <el-button
            v-if="scope.row.level === 3"
            type="text"
            size="mini"
            @click="
              () => {
                dialogPermissionFormVisible = true;
                permissionForm = { ...PERMISSION_FORM };
                permissionForm.pid = scope.row.id;
                permissionTitle = '添加功能';
              }
            "
          >
            添加功能</el-button
          >
          <el-button
            v-if="scope.row.level === 4"
            type="text"
            size="mini"
            @click="updatePermissionDialog(scope.row)"
            >修改功能</el-button
          >
          <el-button
            v-if="scope.row.level !== 1 && scope.row.level !== 4"
            type="text"
            size="mini"
            @click="addOrEditMenuDialog(scope.row, 'edit')"
            >修改</el-button
          >
          <el-button
            v-if="scope.row.level !== 1"
            @click="deleteSubmit(scope.row)"
            type="text"
            size="mini"
            >删除</el-button
          >
        </template>
      </el-table-column>
    </el-table>
    <!-- 添加菜单的窗口 -->
    <el-dialog
      :title="title"
      :label-position="labelPosition"
      :visible.sync="dialogFormVisible"
    >
      <el-form
        ref="menuForm"
        :model="menuForm"
        :rules="menuFormRules"
        label-width="120px"
      >
        <el-form-item label="菜单名称" prop="name">
          <el-input v-model="menuForm.name"></el-input>
        </el-form-item>
        <el-form-item label="访问路径" prop="path" v-if="showFlag">
          <el-input v-model="menuForm.path"></el-input>
        </el-form-item>
        <el-form-item label="组件路径" prop="component" v-if="showFlag">
          <el-input v-model="menuForm.component"></el-input>
        </el-form-item>
        <!-- <el-form-item label="权限值" prop="permissionValue">
          <el-input v-model="menuForm.permissionValue"></el-input>
        </el-form-item> -->
        <el-form-item label="图标" prop="icon">
          <el-input v-model="menuForm.icon"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="resetMenu()">取 消</el-button>
        <el-button type="primary" @click="addMenuFormSubmit()">确 定</el-button>
      </div>
    </el-dialog>


    <!-- 添加功能的窗口 -->
    <el-dialog
      :title="permissionTitle"
      :label-position="labelPosition"
      :visible.sync="dialogPermissionFormVisible"
    >
      <el-form
        ref="permissionForm"
        :model="permissionForm"
        :rules="permissionFormRules"
        label-width="120px"
      >
        <el-form-item label="功能名称" prop="name">
          <el-input v-model="permissionForm.name"></el-input>
        </el-form-item>
        <el-form-item label="访问路径" prop="path">
          <el-input v-model="permissionForm.path"></el-input>
        </el-form-item>
        <el-form-item label="组件路径" prop="component">
          <el-input v-model="permissionForm.component"></el-input>
        </el-form-item>
        <el-form-item label="功能权限值" prop="permissionValue">
          <el-input v-model="permissionForm.permissionValue"></el-input>
        </el-form-item>
        <el-form-item label="图标" prop="icon">
          <el-input v-model="permissionForm.icon"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="resetPermission()">取 消</el-button>
        <el-button type="primary" @click="addPermissonFormSubmit()"
          >确 定</el-button
        >
      </div>
    </el-dialog>
  </div>
</template>
<script>
import { getData, updateMenuSubmit, deleteSubmit } from "@/api/permission.js";
import http from "@/utils/request";
const MENU_FORM = {
  name: "",
  path: "",
  component: "",
  // status: 0,
  icon: "setting",
  pid: 0,
  type: "1",
  id: "",
};
const PERMISSION_FORM = {
  name: "",
  path: "",
  component: "",
  permissionValue: "",
  // status: 0,
  icon: "setting",
  pid: 0,
  type: "2",
  id: "",
};
export default {
  data() {
    return {
      showFlag: true,
      labelPosition: "left",
      tableData: [], //获取递归取得的全部菜单
      dialogFormVisible: false, //添加修改菜单窗口开关
      dialogPermissionFormVisible: false, //添加修改功能窗口开关
      title: "添加菜单", //添加修改菜单标题
      permissionTitle: "添加功能", //添加修改菜单标题
      menuForm: MENU_FORM, //添加修改菜单内容
      permissionForm: PERMISSION_FORM, //添加修改功能内容
      //表单验证
      menuFormRules: {
        name: [
          { required: true, message: "请输入菜单名称", trigger: "blur" },
          {
            min: 3,
            max: 30,
            message: "长度在 3 到 30 个字符",
            trigger: "blur",
          },
        ],
        path: [
          { message: "请输入访问路径", trigger: "blur" },
          {
            min: 3,
            max: 18,
            message: "长度在 3 到 18 个字符",
            trigger: "blur",
          },
        ],
        component: [
          { message: "请输入组件路径", trigger: "blur" },
          {
            min: 3,
            max: 18,
            message: "长度在 3 到 18 个字符",
            trigger: "blur",
          },
        ],
      },
      //功能表单验证
      permissionFormRules: {
        name: [
          { required: true, message: "请输入菜单名称", trigger: "blur" },
          { min: 3, max: 8, message: "长度在 3 到 8 个字符", trigger: "blur" },
        ],


        permissionValue: [
          { required: true, message: "请输入权限值", trigger: "blur" },
          {
            min: 3,
            max: 18,
            message: "长度在 3 到 18 个字符",
            trigger: "blur",
          },
        ],
      },
    };
  },


  created() {
    //获取递归取得的全部菜单
    this.getAllMenuList();
  },
  methods: {
    //修改功能
    updatePermissionDialog(val) {
      this.dialogPermissionFormVisible = true;
      this.permissionForm = val;
      this.permissionTitle = "修改功能";
    },
    //取消菜单添加或修改
    resetMenu() {
      this.dialogFormVisible = false;
      this.menuForm = {};
    },


    //取消功能添加或修改
    resetPermission() {
      this.dialogPermissionFormVisible = false;
      this.permissionForm = {};
    },
    //添加修改下级功能
    addPermissonFormSubmit() {
      let that = this;
      this.$refs.permissionForm.validate((valid) => {
        if (valid) {
          if (that.permissionForm.id) {
            //修改
            updateMenuSubmit(that.permissionForm).then((res) => {
              if (res.code === 20000) {
                that.$message({
                  type: "success",
                  message: "修改功能成功",
                });
                //刷新页面
                that.getAllMenuList();
                that.dialogPermissionFormVisible = false;
                that.permissionForm = { ...PERMISSION_FORM };
              }
            });
          } else {
            //新增


            //let permission = that.menuForm;
            http({
              url: "/permission/save",
              method: "post",
              data: that.permissionForm,
            }).then((res) => {
              if (res.code === 20000) {
                that.$message({
                  type: "success",
                  message: "添加功能成功",
                });
                //刷新页面
                that.getAllMenuList();
                that.dialogPermissionFormVisible = false;
                that.permissionForm = { ...PERMISSION_FORM };
              }
            });
          }
        } else {
          return false;
        }
      });
    },
    //删除
    deleteSubmit(val) {
      let that = this;
      this.$confirm("此操作将永久删除该记录,是否继续?", "提升", {
        distinguishCancelAndClose: true,
        confirmButtonText: "确定",
        cancelButtonText: "取消",
      })
        .then(() => {
          deleteSubmit(val.id).then((res) => {
            if (res.code === 20000) {
              that.$message({
                type: "success",
                message: "删除成功",
              });
              //刷新页面
              that.getAllMenuList();
            }
          });
          this.$message({
            type: "info",
            message: "保存修改",
          });
        })
        .catch((action) => {
          this.$message({
            type: "info",
            message:
              action === "cancel" ? "放弃保存并离开页面" : "停留在当前页面",
          });
        });
      // let that = this;
      // this.$confirm("此操作将永久删除该记录,是否继续?", "提升", {
      //   cofirmButtonText: "确定",
      //   cancelButtonText: "取消",
      //   type: "warning",
      // }).then(() => {
      //   deleteSubmit(val.id).then((res) => {
      //     if (res.code === 20000) {
      //       that.$message({
      //         type: "success",
      //         message: "删除成功",
      //       });
      //       //刷新页面
      //       that.getAllMenuList();
      //     }
      //   });
      // });
    },
    //修改
    updateMenuSubmit() {
      let that = this;
      updateMenuSubmit(that.menuForm).then((res) => {
        if (res.code === 20000) {
          that.$message({
            type: "success",
            message: "修改菜单成功",
          });
          //刷新页面
          that.getAllMenuList();
          that.dialogFormVisible = false;
        }
      });
    },
    //新增
    addMenuSubmit() {
      let that = this;
      //let permission = that.menuForm;
      http({
        url: "/admin/sys/permission/save",
        method: "post",
        data: that.menuForm,
      }).then((res) => {
        if (res.code === 20000) {
          that.$message({
            type: "success",
            message: "添加菜单成功",
          });
          //刷新页面
          that.getAllMenuList();
          that.dialogFormVisible = false;
        }
      });
    },
    //提交添加菜单的数据
    addMenuFormSubmit() {
      let that = this;
      this.$refs.menuForm.validate((valid) => {
        if (valid) {
          if (that.menuForm.id) {
            that.title = "修改菜单";
            //修改
            that.updateMenuSubmit();
          } else {
            that.title = "添加菜单";
            //新增
            that.addMenuSubmit();
          }
        } else {
          return false;
        }
      });
    },
    //显示添加菜单
    addOrEditMenuDialog(val, flag) {
      if (val.level === 1) {
        this.showFlag = false;
      } else {
        this.showFlag = true;
      }


      if ("add" === flag) {
        //新增的话,页面的值初始化为定义好的常量
        this.menuForm = { ...MENU_FORM };
        //新增的话,新增的菜单的pid为当前选中的行的id
        this.menuForm.pid = val.id;
        this.title = "添加菜单";
      } else {
        this.title = "修改菜单";
        //修改的话,页面的值初始化为列表的具体的内容
        Object.assign(this.menuForm, val);
        //修改
        if (val.level === 2) {
          this.showFlag = false;
        }
      }


      this.dialogFormVisible = true;
    },
    //获取递归取得的全部菜单
    getAllMenuList() {
      getData().then((res) => {
        if (res.code === 20000 && res.data) {
          this.tableData = res.data.data;
          //console.log('JSON.stringify(this.tableData) ==='+JSON.stringify(this.tableData))
        }
      });
    },
  },
};
</script>

分配权限

<template>
  <div style="margin: 29px">
    <el-tree
      ref="tree"
      :data="data"
      show-checkbox
      default-expand-all
      node-key="id"
      highlight-current
      :props="defaultProps"
    />
    <el-button :disabled="saveBtnDisabled" type="primary" @click="save"
      >保存</el-button
    >
  </div>
</template>


<script>
import {
  toAssign,
  doAssign,
} from "@/api/permission";
export default {
  data() {
    return {
      saveBtnDisabled: false,
      data: [],
      roleId: "",
      defaultProps: {
        children: "children",
        label: "name",
      },
    };
  },
  watch: {
    $route(to, from) {
      this.init();
    },
  },
  created() {
    this.init();
  },
  methods: {
    init() {
      if (this.$route.params && this.$route.params.id) {
        this.roleId = this.$route.params.id;
        this.getDataList(this.roleId);
      }
    },
    getDataList(roleId) {
      toAssign(roleId).then((res) => {
        if (res.code === 20000 && res.data.data) {
          this.data = res.data.data;
          var list = [];
          var jsonList = JSON.parse(JSON.stringify(this.data));
          var llll = JSON.stringify(this.data);
          console.log("this.data=========================  " + this.data);
          console.log("jsonList=========================  " + jsonList);
          console.log(
            "JSON.stringify(this.data)=========================  " +
              JSON.stringify(this.data)
          );
          this.getJsonList(list, jsonList[0]["children"]);
          this.$refs.tree.setCheckedKeys(list);
        }
      });
    },
    //获取所有的角色的权限
    getJsonList(list, jsonList) {
      for (var i = 0; i < jsonList.length; i++) {
        if (
          jsonList[i]["hasSelect"] == true &&
          jsonList[i]["children"].length === 0
        ) {
          list.push(jsonList[i]["id"]);
        }
        if (jsonList[i]["children"].length > 0) {
          this.getJsonList(list, jsonList[i]["children"]);
        }
      }
    },
    save() {
      this.saveBtnDisabled = true;
      var beforeIds = this.$refs.tree.getHalfCheckedKeys().join(",");
      var afterIds = this.$refs.tree.getCheckedKeys().join(",");
      var ids = beforeIds + "," + afterIds;
      if (ids === ",") {
        ids = [];
      }
      console.log(ids);
      doAssign(this.roleId, ids).then((res) => {
        if (res.code === 20000 && res.success) {
          this.$message({
            type: "info",
            message: "保存成功!",
          });
          this.$router.push({ path: "/role" });
        } else {
          this.$message({
            type: "info",
            message: "保存失败!",
          });
        }
      });
    },
  },
};
</script>


<style>
</style>

路由

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '@/views/Home.vue'
import User from '@/views/sys/user/User.vue'
import Main from '@/views/Main.vue'
import store from '@/store'
import { getToken } from '@/utils/auth'
import { login, logout, getInfo } from '@/api/login'
Vue.use(VueRouter)


// 0. 如果使用模块化机制编程,导入Vue和VueRouter,要调用 Vue.use(VueRouter)
// 1. 定义 (路由) 组件。
// 可以从其他文件 import 进来
// 2. 定义路由
// 每个路由应该映射一个组件。 其中"component" 可以是
// 通过 Vue.extend() 创建的组件构造器,
// 或者,只是一个组件配置对象。
// 我们晚点再讨论嵌套路由。
const routes = [
  {
    path: '/login',
    name: 'Login',
    component: () => import('@/views/Login.vue')
  },
  //主路由
  // {
  //   path: '/',
  //   component: Main,
  //   redirect: '/home',
  //   children: [
  //     //子路由
  //     { path: 'home', name: "home", component: Home },//首页
  //     // { path: 'user', name: "user", component: User },//用户管理
  //     // { path: 'role', name: "role", component: () => import("@/views/sys/Role.vue") },//角色管理
  //     // { path: 'menu', name: "menu", component: () => import("@/views/sys/Menu.vue") },//菜单管理管理
  //   ]
  // },
  // {
  //   path: '/user',
  //   name: 'User',
  //   component: User
  // },
]


// 3. 创建 router 实例,然后传 `routes` 配置
// 你还可以传别的配置参数, 不过先这么简单着吧。
const router = new VueRouter({
  mode: 'history', // 去掉url中的#
  routes // (缩写) 相当于 routes: routes
})


// 4. 创建和挂载根实例。挂载到main.js的根节点
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
// const app = new Vue({
//   router
// }).$mount('#app')


// 防止连续点击多次路由报错
// 获取原型对象push函数
const originalPush = VueRouter.prototype.push
// 获取原型对象replace函数
const originalReplace = VueRouter.prototype.replace
// 修改原型对象中的push函数
VueRouter.prototype.push = function push(location) {
  return originalPush.call(this, location).catch(err => err)
}
// 修改原型对象中的replace函数
VueRouter.prototype.replace = function replace(location) {
  return originalReplace.call(this, location).catch(err => err)
}


//模拟菜单数据
//const authoritys = ['sys:user:list', "sys:user:save", "sys:user:delete"]


const menuData1 = [
  // {
  //   path: "/",
  //   name: "home",
  //   label: "首页",
  //   icon: "s-home",
  //   url: "Home/Home",
  // },
  {
    label: "权限管理",
    name: "system",
    icon: "location",
    children: [
      {
        path: "/user",
        name: "user",
        label: "用户管理",
        icon: "setting",
        component: "sys/user/User",
      },
      {
        path: '/sys/role/distribution/:id',
        name: '角色权限',
        component: 'sys/role/roleForm',
        meta: { title: '角色权限', icon: 'table' },
        hidden: true
      },
      {
        path: '/userForm/:id',
        name: '角色权限',
        component: 'sys/user/userForm',
        meta: { title: '角色权限', icon: 'table' },
        hidden: true
      },
      {
        path: "/role",
        name: "role",
        label: "角色管理",
        icon: "setting",
        component: "sys/role/Role",
      },
      {
        path: "/menu",
        name: "menu",
        label: "菜单管理",
        icon: "setting",
        component: "sys/menu/Menu",
      },
    ],
  },
]
// 拼装动态路由
const manageRoute = {
  path: '/',
  component: Main,
  redirect: '/login',
  children: [
    //子路由
    { path: 'home', name: "home", component: Home },//首页


  ]
}
//获取数据
//菜单
// store.commit('setMenuList', menuData1)


//权限用户
//localStorage.setItem("menus1", JSON.stringify(menuData1))
// 注意:刷新页面会导致页面路由重置
const setRoutes = () => {


  //const storeMenus = localStorage.getItem("menus");
  const storeMenus = localStorage.getItem("menus");


  if (storeMenus) {


    // 获取当前的路由对象名称数组
    const currentRouteNames = router.getRoutes().map(v => v.name)
    if (!currentRouteNames.includes('home')) {
      
      const menus = JSON.parse(storeMenus)
      menus.forEach(item => {
        
        if (item.path) {  // 当且仅当path不为空的时候才去设置路由
          
          let flag = false;
          if (item.hidden) {


            flag = true;
          }
          let itemMenu = {
            path: item.path,
            name: item.name,
            hidden: flag,
            component: () => import('../views/' + item.component + '.vue')
          }
 
          manageRoute.children.push(itemMenu)
        } else if (item.children.length) {
          item.children.forEach(item => {
            let flag = false;
            if (item.hidden) {


              flag = true;
            }
            if (item.path) {
              let itemMenu = {
                path: item.path,
                name: item.name,
                hidden: flag,
                component: () => import('../views/' + item.component + '.vue')
              }


              manageRoute.children.push(itemMenu)
            }
          })
        }
      })
      
      // 动态添加到现在的路由对象中去
      router.addRoute(manageRoute)
    }


  }
}


// 重置我就再set一次路由
setRoutes()


//转成路由
// const menuToRoute = (item) => {


//   if (!item.component) {
//     return null
//   }
//   // let route = {
//   //   name: item.name,
//   //   path: item.path.replace("/", ""),


//   //   meta: {
//   //     icon: item.icon,
//   //     title: item.title,


//   //   }
//   // }
//   // route.component= () => import('../views/' + item.component + '.vue')
//   // route.component=()=>import('@/views/'+item.component+'.vue');
//   // route.component = () => import('@/views/' + item.component + '.vue')
//   let route = { path: item.path.replace("/", ""), name: item.name, component: () => import('../views/' + item.component + '.vue') }
//   return route
// }






// router.beforeEach((to, from, next) => {


//   let that = this


//   getInfo(store.state.token).then(response => {
    
//     const data = response.data
//     if (data.roles && data.roles.length > 0) { // 验证返回的roles是否是一个非空数组
//       store.commit('SET_ROLES', data.roles)
//     }


//     const buttonAuthList = []
//     menuData = data.permissionList
//     
//     data.permissionValueList.forEach(button => {
//       if (button) {
//         buttonAuthList.push(button)
//       }


//     })


//     store.commit('SET_NAME', data.name)
//     //commit('SET_AVATAR', data.avatar)
//     store.commit('SET_BUTTONS', buttonAuthList)


//   }).catch(error => {


//   })
//   next()
// })




export default router

权限

import router from './router'
import { login, logout, getInfo } from '@/api/login'
import { getToken, setToken, removeToken } from '@/utils/auth'
import http from "@/utils/request";
import qs from "qs";
import store from './store'
router.beforeEach(async (to, from, next) => {




  const hasToken = getToken()


  if (hasToken) {
    if (to.path === '/login') {
      // if is logged in, redirect to the home page
      next()


    } else {
      // determine whether the user has obtained his permission roles through getInfo
      const hasRoles = store.getters.roles && store.getters.roles.length > 0
      if (hasRoles) {
        next()
      } else {
        // get user info
        // note: roles must be a object array! such as: ['admin'] or ,['developer','editor']
        const response = await store.dispatch('GetInfo')
        if (response.code === 20000) {
          const data = response.data
          if (data.roles && data.roles.length > 0) { // 验证返回的roles是否是一个非空数组
            store.commit('SET_ROLES', data.roles)
          }


          const buttonAuthList = []
          const menuData = data.permissionList
          store.commit('setMenuList', menuData)


          //权限用户
          localStorage.setItem("menus", JSON.stringify(menuData))
          data.permissionValueList.forEach(button => {
            if (button) {
              buttonAuthList.push(button)
            }


          })


          store.commit('SET_NAME', data.name)
          //commit('SET_AVATAR', data.avatar)
          store.commit('SET_BUTTONS', buttonAuthList)




        }


      }
    }
  }
  next()
})

mixin

import Vue from "vue"


Vue.mixin({
  methods: {
    hasAuth(perm) {
      var authority = this.$store.state.user.buttons
      return authority.indexOf(perm) > -1
    }
  }
})

security配置

package com.stu.myserver.config;




import com.stu.myserver.security.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;


/******************************
 * 用途说明: Security配置
 * 作者姓名: 公众号:小明的学习圈子  https://www.stucoding.com/
 * 创建时间: 2022-07-27 23:16
 ******************************/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    LoginFailureHandler loginFailureHandler;


    @Autowired
    LoginSuccessHandler loginSuccessHandler;


    @Autowired
    CaptchaFilter captchaFilter;
    
    @Autowired
    JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;


    @Autowired
    JwtAccessDeniedHandler jwtAccessDeniedHandler;


    @Autowired
    private UserDetailsService userDetailsService;


    @Autowired
    JwtLogoutSuccessHandler jwtLogoutSuccessHandler;


    @Bean
    JwtAuthenticationFilter jwtAuthenticationFilter() throws Exception {
        JwtAuthenticationFilter jwtAuthenticationFilter = new JwtAuthenticationFilter(authenticationManager());
        return jwtAuthenticationFilter;
    }


    //    @Bean
//    BCryptPasswordEncoder bCryptPasswordEncoder() {
//        return new BCryptPasswordEncoder();
//    }
    private static final String[] URL_WHITELIST = {


            "/user/register",
            "/js/**",
            "/login",
            "/logout",
            "/captcha",
            "/favicon.ico",
            "/login**",
            "/login#/login",
            "/home/getData",
            "captcha/getUserInfo"


    };


    protected void configure(HttpSecurity http) throws Exception {


        http.cors().and().csrf().disable()                // 登录配置
                .formLogin()
                .successHandler(loginSuccessHandler)
                .failureHandler(loginFailureHandler)


                .and()
                .logout()
                .logoutSuccessHandler(jwtLogoutSuccessHandler)


                // 禁用session
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)


                // 配置拦截规则
                .and()
                .authorizeRequests()
                .antMatchers(URL_WHITELIST).permitAll()
                .anyRequest().authenticated()


                // 异常处理器
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(jwtAuthenticationEntryPoint)
                .accessDeniedHandler(jwtAccessDeniedHandler)


                // 配置自定义的过滤器
                .and()
                .addFilter(jwtAuthenticationFilter())
                .addFilterBefore(captchaFilter, UsernamePasswordAuthenticationFilter.class);






    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }
}

Redis配置

package com.stu.myserver.config;




import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;


/******************************
 * 用途说明: redis配置
 * 作者姓名: 公众号:小明的学习圈子  https://www.stucoding.com/
 * 创建时间: 2022-07-27 23:16
 ******************************/
@Configuration
public class RedisConfig {


    @Bean
    RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {


        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory);


        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        jackson2JsonRedisSerializer.setObjectMapper(new ObjectMapper());


        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);


        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);


        return redisTemplate;


    }


}

跨域配置

package com.stu.myserver.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;




/******************************
 * 用途说明: 跨域
 * 作者姓名: 公众号:小明的学习圈子  https://www.stucoding.com/
 * 创建时间: 2022-07-27 23:16
 ******************************/
@Configuration
public class CorsConfig implements WebMvcConfigurer {
    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addExposedHeader("Authorization");
        return corsConfiguration;
    }


    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig());
        return new CorsFilter(source);
    }


    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
//          .allowCredentials(true)
                .allowedMethods("GET", "POST", "DELETE", "PUT")
                .maxAge(3600);
    }
}
PermissionServiceImpl
package com.stu.myserver.service.impl;


import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.stu.myserver.entity.Permission;
import com.stu.myserver.entity.RolePermission;
import com.stu.myserver.mapper.PermissionMapper;
import com.stu.myserver.service.IPermissionService;
import com.stu.myserver.service.IRolePermissionService;
import com.stu.myserver.service.IUserService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.stu.myserver.entity.User;
import org.springframework.util.CollectionUtils;


import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;


/**
 * <p>
 * 权限 服务实现类
 * </p>
 *
 * @author 程序员小明1024
 * @since 2023-08-07
 */
@Service
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements IPermissionService {


    @Autowired
    private IRolePermissionService rolePermissionService;


    @Autowired
    private IUserService userService;


    /***********************************
     * 用途说明:获取全部菜单
     * 返回值说明:
     * @return List<Permission>
     ***********************************/
    @Override
    public List<Permission> listPermissions() {
        QueryWrapper<Permission> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("id");


        //把查询的所有菜单用递归的方式生成结构化菜单
        return buildPermissions(baseMapper.selectList(queryWrapper));
    }


    /***********************************
     * 用途说明:获取全部菜单
     * 返回值说明:
     * @return List<Permission>
     ***********************************/
    private List<Permission> buildPermissions(List<Permission> list) {
        //创建rootList集合,最终数据封装
        List<Permission> rootList = new ArrayList<>();


        //遍历所有菜单,得到顶层菜单 pid==0,设置leve =1
        for (Permission permission : list) {
            //获取顶层菜单,pid=0
            if ("0".equals(permission.getPid())) {
                //设置level = 1
                permission.setLevel(1);
                //根据顶层菜单,添加子菜单,封装到rootList
                rootList.add(selectChildrenMenu(permission, list));


            }
        }


        return rootList;
    }


    /***********************************
     * 用途说明:递归查询下级菜单
     * @param root
     * @param list
     * 返回值说明:
     * @return com.stu.myserver.entity.Permission
     ***********************************/
    private Permission selectChildrenMenu(Permission root, List<Permission> list) {
        //因为要往下级菜单房新的菜单,需要初始化
        root.setChildren(new ArrayList<Permission>());
        //遍历所有菜单,比较当前对象的id和遍历的子菜单的pid是否相同
        for (Permission permission : list) {
            if (root.getId().equals(permission.getPid())) {
                permission.setLevel(root.getLevel() + 1);
                //递归,查询出来的子菜单放到父菜单里
                root.getChildren().add(selectChildrenMenu(permission, list));
            }
        }
        return root;
    }


    /***********************************
     * 用途说明:查询所有权限菜单
     * 返回值说明:
     * @return java.util.List<com.stu.service.acl.entity.Permission>
     ***********************************/
    @Override
    public List<Permission> ListAllPermissions() {
        QueryWrapper<Permission> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("id");
        return bulidPermission(baseMapper.selectList(queryWrapper));
    }


    /***********************************
     * 用途说明:把返回所有菜单list集合进行封装的方法
     * @param list
     * 返回值说明:
     * @return java.util.List<com.stu.service.acl.entity.Permission>
     ***********************************/
    private List<Permission> bulidPermission(List<Permission> list) {
        //创建list集合,用于数据最终封装
        List<Permission> finalNode = new ArrayList<>();


        //把所有菜单list集合遍历,得到顶层菜单 pid=0菜单,设置level是1
        for (Permission permission : list) {
            //得到顶层菜单 pid=0菜单
            if ("0".equals(permission.getPid())) {
                permission.setLevel(1);
                //根据顶层菜单,向里面进行查询子菜单,封装到finalNode里面
                finalNode.add(selectChildren(permission, list));
            }
        }


        return finalNode;
    }


    /***********************************
     * 用途说明:递归查询下级菜单
     * @param permission
     * @param list
     * 返回值说明:
     * @return com.stu.service.acl.entity.Permission
     ***********************************/
    private Permission selectChildren(Permission permission, List<Permission> list) {
        //1 因为向一层菜单里面放二层菜单,二层里面还要放三层,把对象初始化
        permission.setChildren(new ArrayList<Permission>());
        //2 遍历所有菜单list集合,进行判断比较,比较id和pid值是否相同
        for (Permission child : list) {
            if (permission.getId().equals(child.getPid())) {
                child.setLevel(permission.getLevel() + 1);
                if (child.getChildren() == null) {
                    child.setChildren(new ArrayList<>());
                }
//                permission.getChildren().add(child);
//                selectChildren(child,list);
                permission.getChildren().add(selectChildren(child, list));
            }
        }
        return permission;


    }


    /***********************************
     * 用途说明:递归删除菜单
     * @param id
     * 返回值说明:
     * @return boolean
     ***********************************/
    @Override
    public boolean removeChildById(String id) {
        List<String> idList = new ArrayList<>();
        selectChildListById(id, idList);
        idList.add(id);
        return baseMapper.deleteBatchIds(idList) > 0;
    }


    /***********************************
     * 用途说明:根據角色獲取菜單
     * @param id
     * 返回值说明:
     * @return java.util.List<com.stu.service.acl.entity.Permission>
     ***********************************/
    @Override
    public List<Permission> listAllMenu(String id) {
        //获取所有菜单
        List<Permission> allPermissionList = baseMapper.selectList(new QueryWrapper<>());
        //根据角色id呼气角色权限列表
        List<RolePermission> rolePermissionsList = rolePermissionService
                .list(new QueryWrapper<RolePermission>().eq("role_id", id));
        //遍历所有菜单,获取每一项,看是否在权限列表,如果在,就标记
        List<String> permissionIdList = rolePermissionsList.stream().map(e -> e.getPermissionId()).collect(Collectors.toList());
        allPermissionList.forEach(permission -> {
            if (permissionIdList.contains(permission.getId())) {
                permission.setHasSelect(true);
            } else {
                permission.setHasSelect(false);
            }
        });
        /*for (int i = 0; i < allPermissionList.size(); i++) {
            Permission permission = allPermissionList.get(i);
            for (int m = 0; m < rolePermissionList.size(); m++) {
                RolePermission rolePermission = rolePermissionList.get(m);
                if(rolePermission.getPermissionId().equals(permission.getId())) {
                    permission.setSelect(true);
                }
            }
        }*/
        return bulidPermission(allPermissionList);
    }


    /***********************************
     * 用途说明:给角色分配菜单权限
     * @param roleId
     * @param permissionId
     * 返回值说明:
     * @return boolean
     ***********************************/
    @Override
    public boolean saveRolePermissionrelationShip(String roleId, String[] permissionId) {


        //删除旧的权限
       boolean ttt =  rolePermissionService.remove(new QueryWrapper<RolePermission>().eq("role_id", roleId));
        if (null != permissionId && permissionId.length > 0) {
            List<RolePermission> list = new ArrayList<>();
            for (String id : permissionId) {
                RolePermission rolePermission = new RolePermission();
                rolePermission.setRoleId(roleId);
                rolePermission.setPermissionId(id);
                list.add(rolePermission);
            }


            return rolePermissionService.saveBatch(list);
        }
        return true;
    }


    /***********************************
     * 用途说明:根据用户id查询有权限的菜单
     * @param id
     * 返回值说明:
     * @return java.util.List<java.lang.String>
     ***********************************/
    @Override
    public List<String> selectPermissionValueListByUserId(String id) {
        List<String> list;
        if (checkAdmin(id)) {
            //如果是超级管理员获取所有权限
            list = baseMapper.selectAllPermissionValue();
        } else {
            //根据用户id查询所有权限
            list = baseMapper.selectPermissionValueByUserId(id);
        }
        return list;
    }


    /***********************************
     * 用途说明:根据用户id查询所有权限的菜单详细列表
     * @param userId
     * 返回值说明:
     * @return java.util.List<org.json.JSONObject>
     ***********************************/
    @Override
    public List<JSONObject> selectPermissionByUserId(String userId) {
        List<Permission> selectPermissionList = null;
        if (checkAdmin(userId)) {
            //如果是超级管理员获取所有权限
            selectPermissionList = baseMapper.selectList(null);
        } else {
            //根据用户id查询所有权限
            selectPermissionList = baseMapper.selectPermissionByUserId(userId);
        }
        //先转换成树状
        List<Permission> permissionList = bulidPermission(selectPermissionList);
        //然后转化成前端需要的格式
        List<JSONObject> result = bulidJson(permissionList);


        return result;
    }


    /***********************************
     * 用途说明:转化成前端需要的格式
     * @param permissionList
     * 返回值说明:
     * @return java.util.List<org.json.JSONObject>
     ***********************************/
    private List<JSONObject> bulidJson(List<Permission> permissionList) {
        List<JSONObject> menus = new ArrayList<>();
        if (permissionList.size() == 1) {
            Permission topNode = permissionList.get(0);
            //组建左侧一级菜单
            List<Permission> oneMenuList = topNode.getChildren();
            for (Permission one : oneMenuList) {
                JSONObject oneMenu = new JSONObject();
                oneMenu.put("path", one.getPath());
                oneMenu.put("component", one.getComponent());
                oneMenu.put("redirect", "noredirect");//第一级不需要重定向
                oneMenu.put("name", "name_" + one.getId());
                oneMenu.put("title", one.getName());
                oneMenu.put("label", one.getName());
                oneMenu.put("icon", one.getIcon());
                oneMenu.put("hidden", false);//一级不需要因此,3级需要
                JSONObject oneMeta = new JSONObject();
                oneMeta.put("title", one.getName());
                oneMeta.put("icon", one.getIcon());
                oneMenu.put("meta", oneMeta);


                List<JSONObject> children = new ArrayList<>();
                List<Permission> twoMenuList = one.getChildren();//二级菜单
                for (Permission two : twoMenuList) {
                    JSONObject twoMenu = new JSONObject();
                    twoMenu.put("path", two.getPath());
                    twoMenu.put("component", two.getComponent());
                    twoMenu.put("title", two.getName());
                    twoMenu.put("label", two.getName());
                    twoMenu.put("icon", two.getIcon());
//                    twoMenu.put("redirect", "noredirect");//第一级不需要重定向
                    twoMenu.put("name", "name_" + two.getId());
                    twoMenu.put("hidden", false);//一级不需要因此,3级需要
                    JSONObject twoMeta = new JSONObject();
                    twoMeta.put("title", two.getName());
                    twoMeta.put("icon", two.getIcon());
                    twoMenu.put("meta", twoMeta);
                    children.add(twoMenu);


                    //功能按钮
                    List<Permission> threeMenuList = two.getChildren();
                    for (Permission three : threeMenuList) {
                        if (StringUtils.isEmpty(three.getPath())) {
                            continue;
                        }
                        JSONObject threeMenu = new JSONObject();
                        threeMenu.put("path", three.getPath());
                        threeMenu.put("component", three.getComponent());
//                        threeMenu.put("redirect", "noredirect");//第一级不需要重定向
                        threeMenu.put("name", "name_" + three.getId());
                        threeMenu.put("title", three.getName());
                        threeMenu.put("label", three.getName());
                        threeMenu.put("icon", three.getIcon());
                        threeMenu.put("hidden", true);//一级不需要因此,3级需要
                        JSONObject threeMeta = new JSONObject();
                        threeMeta.put("title", three.getName());
                        threeMeta.put("icon", three.getIcon());
                        threeMenu.put("meta", threeMeta);


                        children.add(threeMenu);
                    }


                }
                oneMenu.put("children", children);
                menus.add(oneMenu);


            }
        }
        return menus;
    }


    /***********************************
     * 用途说明:判断是否管理员
     * @param id
     * 返回值说明:
     * @return boolean
     ***********************************/
    private boolean checkAdmin(String id) {
        User user = userService.getById(id);
        if (user != null && "admin".equals(user.getUsername())) {
            return true;
        }
        return false;
    }


    /***********************************
     * 用途说明:根据当前菜单id查询他的子子孙孙id,封装到list集合
     * @param id
     * @param idList
     * 返回值说明:
     ***********************************/
    private void selectChildListById(String id, List<String> idList) {
        //查询当前菜单的下级
        QueryWrapper<Permission> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("pid", id);
        queryWrapper.select("id");
        List<Permission> childList = baseMapper.selectList(queryWrapper);
        //把childIdList里面菜单id值获取出来,封装idList里面,做递归查询
        childList.forEach(item -> {
            idList.add(item.getId());
            selectChildListById(item.getId(), idList);
        });


    }
}

IndexServiceImpl

package com.stu.myserver.service.impl;


import com.alibaba.fastjson.JSONObject;


import com.stu.myserver.entity.Role;
import com.stu.myserver.entity.User;
import com.stu.myserver.exception.CustomException;
import com.stu.myserver.service.IPermissionService;
import com.stu.myserver.service.IRoleService;
import com.stu.myserver.service.IUserService;
import com.stu.myserver.service.IndexService;
import com.stu.myserver.utils.ResultCodeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;


import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/******************************
 * 用途说明:
 * 作者姓名: Administrator
 * 创建时间: 2022-09-01 22:34
 ******************************/
@Service
public class IndexServiceImpl implements IndexService {


    @Autowired
    private IUserService userService;


    @Autowired
    private IRoleService roleService;


    @Autowired
    private IPermissionService permissionService;


    @Autowired
    private RedisTemplate redisTemplate;


    /***********************************
     * 用途说明:根据用户明获取用户登录信息
     * @param userName
     * 返回值说明:
     * @return java.util.Map<java.lang.String, java.lang.Object>
     ***********************************/
    @Override
    public Map<String, Object> getUserInfo(String userName) {
        Map<String, Object> result = new HashMap<>();
        User user = userService.selectByUserName(userName);
        if (user == null) {
            throw new CustomException(ResultCodeEnum.FETCH_USERINFO_ERROR);
        }
        //根据用户id获取角色
        List<Role> roleList = roleService.selectRoleByUserId(user.getId());
        //转换成角色名称列表
        List<String> roleNameList = roleList.stream()
                .map(item -> item.getRoleName()).collect(Collectors.toList());


        //前端框架必须返回一个角色,否则报错,如果没有角色,返回一个空角色
        if (roleNameList.size() == 0) {
            roleNameList.add("");
        }


        List<String> permissionValueList = permissionService.selectPermissionValueListByUserId(user.getId());
        redisTemplate.opsForValue().set(userName, permissionValueList);
        List<String> permissionValueLisst = (List<String>) redisTemplate.opsForValue().get(userName);
        result.put("name", user.getUsername());
        result.put("roles", roleNameList);
        result.put("permissionValueList", permissionValueList);
        return result;
    }


    /***********************************
     * 用途说明:根据用户动态获取菜单
     * @param userName
     * 返回值说明:
     * @return java.util.List<org.json.JSONObject>
     ***********************************/
    @Override
    public List<JSONObject> getMenu(String userName) {
        User user = userService.selectByUserName(userName);
        if (user == null) {
            throw new CustomException(ResultCodeEnum.FETCH_USERINFO_ERROR);
        }
        //根据用户动态获取菜单
        return permissionService.selectPermissionByUserId(user.getId());
    }
}

RoleServiceImpl

package com.stu.myserver.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.stu.myserver.entity.Role;
import com.stu.myserver.entity.UserRole;
import com.stu.myserver.mapper.RoleMapper;
import com.stu.myserver.service.IRoleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.stu.myserver.service.IUserRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 程序员小明1024
 * @since 2023-06-28
 */
@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements IRoleService {
    @Autowired
    private IUserRoleService userRoleService;


    /***********************************
     * 用途说明:根据用户获取角色
     * @param userId
     * 返回值说明:
     * @return java.util.List<com.stu.service.acl.entity.Permission>
     ***********************************/
    @Override
    public Map<String, Object> findRoleByUserId(String userId) {
        //获取所有角色
        List<Role> allRoleList = baseMapper.selectList(new QueryWrapper<>());
        //根据用户id获取角色列表
        List<UserRole> existUserRoleList = userRoleService
                .list(new QueryWrapper<UserRole>().eq("user_id", userId).select("role_id"));
        //遍历所有菜单,获取每一项,看是否在权限列表,如果在,就标记
        List<String> existRoleLists = existUserRoleList.stream().map(e -> e.getRoleId()).collect(Collectors.toList());


        List<Role> assignRoles = new ArrayList<>();
        allRoleList.forEach(role -> {
            if (existRoleLists.contains(role.getId())) {
                assignRoles.add(role);
            }
        });


        Map<String, Object> roleMap = new HashMap<>();
        roleMap.put("assignRoles", assignRoles);
        roleMap.put("allRoleList", allRoleList);
        return roleMap;
    }


    /***********************************
     * 用途说明:给用户分配角色权限
     * @param userId
     * @param roleIds
     * 返回值说明:
     * @return boolean
     ***********************************/
    @Override
    public boolean saveUserRelationShip(String userId, String[] roleIds) {
        //删除旧的所有角色权限
        userRoleService.remove(new QueryWrapper<UserRole>().eq("user_id", userId));
        List<UserRole> list = new ArrayList<>();
        for (String id : roleIds) {
            UserRole rolePermission = new UserRole();
            rolePermission.setRoleId(id);
            rolePermission.setUserId(userId);
            list.add(rolePermission);
        }


        return userRoleService.saveBatch(list);
    }


    /***********************************
     * 用途说明:根据userid获取用户信息
     * @param userId
     * 返回值说明:
     * @return java.util.List<com.stu.service.acl.entity.Role>
     ***********************************/
    @Override
    public List<Role> selectRoleByUserId(String userId) {
        //根据用户id获取角色列表
        List<UserRole> userRoleList = userRoleService
                .list(new QueryWrapper<UserRole>().eq("user_id", userId).select("role_id"));
        //遍历所有菜单,获取每一项,看是否在权限列表,如果在,就标记
        List<String> roleIdLists = userRoleList.stream().map(e -> e.getRoleId()).collect(Collectors.toList());
        List<Role> roleList = new ArrayList<>();
        if (roleIdLists.size() > 0) {
            roleList = baseMapper.selectBatchIds(roleIdLists);
        }


        return roleList;
    }
}

CodeGenerator

package com.stu.myserver.utils;


import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.fill.Column;


import java.util.Collections;


/******************************
 * 用途说明:
 * 作者姓名:公众号:程序员小明1024
 * 创建时间: 2023-06-23 14:52
 ******************************/
public class CodeGenerator {


    public static void main(String[] args) {
        generate();
    }


    private static void generate() {
        String projectPath = System.getProperty("user.dir");
        FastAutoGenerator.create("jdbc:mysql://localhost:3306/2023Java?serverTimezone=Asia/Shanghai", "root", "study")
                .globalConfig(builder -> {
                    builder.author("公众号 小明的学习圈子") // 设置作者
                            .enableSwagger() // 开启 swagger 模式
                            .fileOverride() // 覆盖已生成文件
                            .outputDir(projectPath + "/src/main/java"); // 指定输出目录
                })
                .packageConfig(builder -> {
                    builder.parent("com.stu.myserver") // 设置父包名
                            .moduleName(null) // 设置父包模块名
                            .pathInfo(Collections.singletonMap(OutputFile.mapperXml, projectPath + "/src/main/resources/mapper")); // 设置mapperXml生成路径
                })
                .strategyConfig(builder -> {
                    builder.entityBuilder().enableLombok()
                            .addTableFills(new Column("gmt_create", FieldFill.INSERT))
                            .addTableFills(new Column("gmt_modified", FieldFill.INSERT_UPDATE));;
//                    builder.mapperBuilder().enableMapperAnnotation().build();
                    builder.controllerBuilder().enableHyphenStyle()  // 开启驼峰转连字符
                            .enableRestStyle();  // 开启生成@RestController 控制器
                    builder.addInclude("acl_user_role") // 设置需要生成的表名
                            .addTablePrefix("acl_", "sys_"); // 设置过滤表前缀
                })
//                .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                .execute();


    }




}
ResponseUtil
package com.stu.myserver.utils;


import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;


import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


/******************************
 * 用途说明:需要寫入response的數據
 * 作者姓名: Administrator
 * 创建时间: 2022-09-01 20:44
 ******************************/
public class ResponseUtil {




    /*这段代码是一个用于在Java Web应用中向客户端发送JSON响应的方法。让我逐行解释其功能:
            1. `public static void out(HttpServletResponse response, R r)`:
            这是一个公共静态方法,它接受两个参数,一个是`HttpServletResponse`对象,
            另一个是泛型`R`的对象`r`。`HttpServletResponse`对象用于设置HTTP响应的状态码、内容类型和写入响应数据。
            2. `ObjectMapper mapper = new ObjectMapper();`:在方法内部创建了一个Jackson库
            的`ObjectMapper`对象。Jackson库是用于在Java对象和JSON之间进行序列化和反序列化的流行库。
            这个`ObjectMapper`对象将用于将`r`对象转换为JSON格式。
            3. `response.setStatus(HttpStatus.OK.value());`:设置HTTP响应的状态码为200 OK。这表示请求已成功处理。
            4. `response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);`:
            设置HTTP响应的内容类型为"application/json;charset=UTF-8",表示响应体将包含JSON数据,并且使用UTF-8字符编码。
            5. `mapper.writeValue(response.getWriter(), r);`:使用`ObjectMapper`
            将`r`对象序列化为JSON格式,并将其写入`HttpServletResponse`的输出流(通过`response.getWriter()`
            获得的输出流)。这样,JSON数据将作为HTTP响应的内容发送给客户端。
    总之,这段代码的目的是将一个Java对象`r`序列化为JSON格式,并将其作为HTTP响应的内容发送给客户端,
    同时设置响应的状态码和内容类型。这通常用于Web应用程序中的API端点,以便向客户端提供结构化的数据响应。
*/    public static void out(HttpServletResponse response, R r) {
        ObjectMapper mapper = new ObjectMapper();
        response.setStatus(HttpStatus.OK.value());
        response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
        try {
            mapper.writeValue(response.getWriter(), r);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

更多内容阅读原文

GitHub 加速计划 / vu / vue
83
16
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:4 个月前 )
9e887079 [skip ci] 3 个月前
73486cb5 * chore: fix link broken Signed-off-by: snoppy <michaleli@foxmail.com> * Update packages/template-compiler/README.md [skip ci] --------- Signed-off-by: snoppy <michaleli@foxmail.com> Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 6 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐