Ant Design Pro V2动态菜单实现

前言

Ant Design Pro是蚂蚁金服团队出品的一款前端框架,安装完毕后可以看到菜单和路由是静态渲染的,在实际的开发过程中,经常需要根据用户名或者权限生成不同的菜单,下面介绍一下具体的实现过程。

开发环境:

  • 后端:Spring 4.2.1
  • 前端:Ant Design Pro V2
  • jdk:1.8

实现效果

使用admin用户登录时,显示管理员菜单项,使用其它用户登录时,显示普通用户菜单项

前端实现过程

官网文档

在官网中https://v2-pro.ant.design/docs/router-and-nav-cn,有这样一句话:
只需在 models/menu 中发起 http 请求,menuData 是一个 json 数组。只需服务器返回类似格式的 json 即可。

[
  {
    path: '/dashboard',
    name: 'dashboard',
    icon: 'dashboard',
    children: [
      {
        path: '/dashboard/analysis',
        name: 'analysis',
        exact: true,
      },
      {
        path: '/dashboard/monitor',
        name: 'monitor',
        exact: true,
      },
      {
        path: '/dashboard/workplace',
        name: 'workplace',
        exact: true,
      },
    ],
  }
  ...
]

BasicLayout组件中调用model/menu.js

登陆成功后,首先在layouts/BasicLayout.js中通过dva异步调用model/menu.js中的方法获取菜单

class BasicLayout extends React.Component {
  componentDidMount () {
    const {
      dispatch,
      route: { routes, path, authority },
    } = this.props;
    dispatch({
      type: 'user/fetchCurrent',
    });
    dispatch({
      type: 'setting/getSetting',
    });
    dispatch({
      type: 'menu/getMenuData',  // 异步调用model/menu.js中获取菜单的方法
      payload: { routes, path, authority },
    });
  }
}

model/menu.js中引入service

在model/menu.js中定义异步方法

  effects: {
    * getMenuData ({ payload }, { call, put }) {
      const { routes, authority, path } = payload;
      const originalMenuData = memoizeOneFormatter(routes, authority, path);
      // const menuData = filterMenuData(originalMenuData);  //Mock方法
      const menuData = yield call(queryMenus, getUser());  // 后台根据用户名获取自定义菜单
      const breadcrumbNameMap = memoizeOneGetBreadcrumbNameMap(originalMenuData);
      yield put({
        type: 'save',
        payload: { menuData, breadcrumbNameMap, routerData: routes },
      });
    },
  },
  reducers: {
    save (state, action) {
      return {  //更新State
        ...state,
        ...action.payload,
      };
    },
  },

service中定义后端API

创建services/menu.js文件,定义后端API

import request from '@/utils/request';

// eslint-disable-next-line import/prefer-default-export
export async function queryMenus(user) {
  return request(`/api/accounts/${user}/menus`);
}

后端实现过程

定义菜单类

在这个过程中用到了类的递归,调试过程中发现使用@Data注解给children属性赋值时会报错,所以直接在IDEA中右键-Generate-Getter/Setter-全部选中,生成Setter/Getter方法。

public class MenuData {
    private String path;
    private String name;
    private String icon;
    private Boolean exact;
    private Set<MenuData> children = new HashSet<>();

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getIcon() {
        return icon;
    }

    public void setIcon(String icon) {
        this.icon = icon;
    }

    public Boolean getExact() {
        return exact;
    }

    public void setExact(Boolean exact) {
        this.exact = exact;
    }

    public Set<MenuData> getChildren() {
        return children;
    }

    public void setChildren(Set<MenuData> children) {
        this.children = children;
    }
}

定义控制器

定义MenuController.java

  @RequestMapping(value = "/accounts/{user}/menus", method = RequestMethod.GET)
    public ResponseEntity<List<MenuData>> getMenuData(@PathVariable("user") String user) {
        List<MenuData> menusDataList = new ArrayList<>();

        if (user.equals("admin")) {
            //父级菜单
            MenuData parent = new MenuData();
            parent.setExact(true);
            parent.setIcon("dashboard");
            parent.setName("管理员-控制面板");
            parent.setPath("/dashboard");
            parent.setChildren(new HashSet<>());

            //子级菜单
            MenuData child1 = new MenuData();
            child1.setExact(true);
            child1.setIcon("analysis");
            child1.setName("管理员-分析");
            child1.setPath("/dashboard/analysis");
            child1.setChildren(new HashSet<>());

            MenuData child2 = new MenuData();
            child2.setExact(true);
            child2.setIcon("monitor");
            child2.setName("管理员-监控");
            child2.setPath("/dashboard/monitor");
            child2.setChildren(new HashSet<>());

            parent.getChildren().add(child1);
            parent.getChildren().add(child2);
            menusDataList.add(parent);
        } else {
            //父级菜单
            MenuData parent = new MenuData();
            parent.setExact(true);
            parent.setIcon("dashboard");
            parent.setName("普通用户-控制面板");
            parent.setPath("/dashboard");
            parent.setChildren(new HashSet<>());

            //子级菜单
            MenuData child1 = new MenuData();
            child1.setExact(true);
            child1.setIcon("analysis");
            child1.setName("普通用户-分析");
            child1.setPath("/dashboard/analysis");
            child1.setChildren(new HashSet<>());

            MenuData child2 = new MenuData();
            child2.setExact(true);
            child2.setIcon("monitor");
            child2.setName("普通用户-监控");
            child2.setPath("/dashboard/monitor");
            child2.setChildren(new HashSet<>());

            parent.getChildren().add(child1);
            parent.getChildren().add(child2);
            menusDataList.add(parent);
        }
        return new ResponseEntity<>(menusDataList, HttpStatus.OK);
    }

效果验证

后端监测:
在这里插入图片描述

前端监测:
在这里插入图片描述

使用admin用户登录:
在这里插入图片描述

使用user用户登录:
在这里插入图片描述

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值