ruoyi前后端分离版实现嵌套路由,前后端改造方法实现

想实现vue-router的嵌套路由,看了一下若依框架前后端分离版,没有这个功能,于是自定义了一下

在这里插入图片描述

后端

一、改造sysMenu表,添加redirect属性和menuType类型

操作如下:

  1. UserConstants.class 下添加常量
/** 菜单类型(嵌套路由菜单) */
public static final String TYPE_NESTING = "N";
  1. SysMenuServiceImpl.class 下添加修改buildMenus 方法
/**
     * 构建前端路由所需要的菜单
     * 
     * @param menus 菜单列表
     * @return 路由列表
     */
    @Override
    public List<RouterVo> buildMenus(List<SysMenu> menus)
    {
        List<RouterVo> routers = new LinkedList<RouterVo>();
        for (SysMenu menu : menus)
        {
            RouterVo router = new RouterVo();
            router.setHidden("1".equals(menu.getVisible()));
            router.setName(getRouteName(menu));
            router.setPath(getRouterPath(menu));
            router.setComponent(getComponent(menu));
            router.setQuery(menu.getQuery());
            router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
            List<SysMenu> cMenus = menu.getChildren();
            if (StringUtils.isNotEmpty(cMenus) && UserConstants.TYPE_DIR.equals(menu.getMenuType()))
            {
                router.setAlwaysShow(true);
                router.setRedirect("noRedirect");
                router.setChildren(buildMenus(cMenus));
            }
            else if (UserConstants.TYPE_NESTING.equals(menu.getMenuType())){
                router.setRedirect(getRouteRedirect(menu));
                List<RouterVo> routerVos = buildMenus(cMenus);
                routerVos.forEach(routerVo -> {
                    MetaVo meta = routerVo.getMeta();
                    meta.setActiveMenu(menu.getRedirect());
                    meta.setNested(true);
                    routerVo.setMeta(meta);
                });
                router.setChildren(routerVos);
            }
            else if (isMenuFrame(menu))
            {
                router.setMeta(null);
                List<RouterVo> childrenList = new ArrayList<RouterVo>();
                RouterVo children = new RouterVo();
                children.setPath(menu.getPath());
                children.setComponent(menu.getComponent());
                children.setName(StringUtils.capitalize(menu.getPath()));
                children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
                children.setQuery(menu.getQuery());
                childrenList.add(children);
                router.setChildren(childrenList);
            }
            else if (menu.getParentId().intValue() == 0 && isInnerLink(menu))
            {
                router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));
                router.setPath("/");
                List<RouterVo> childrenList = new ArrayList<RouterVo>();
                RouterVo children = new RouterVo();
                String routerPath = innerLinkReplaceEach(menu.getPath());
                children.setPath(routerPath);
                children.setComponent(UserConstants.INNER_LINK);
                children.setName(StringUtils.capitalize(routerPath));
                children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath()));
                childrenList.add(children);
                router.setChildren(childrenList);
            }
            routers.add(router);
        }
        return routers;
    }
  1. SysMenuMapper.xml添加修改的字段
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
		PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
		"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.system.mapper.SysMenuMapper">

	<resultMap type="SysMenu" id="SysMenuResult">
		<id     property="menuId"         column="menu_id"        />
		<result property="menuName"       column="menu_name"      />
		<result property="parentName"     column="parent_name"    />
		<result property="parentId"       column="parent_id"      />
		<result property="orderNum"       column="order_num"      />
		<result property="path"           column="path"           />
		<result property="component"      column="component"      />
		<result property="query"          column="query"          />
		<result property="isFrame"        column="is_frame"       />
		<result property="isCache"        column="is_cache"       />
		<result property="menuType"       column="menu_type"      />
		<result property="visible"        column="visible"        />
		<result property="status"         column="status"         />
		<result property="redirect"       column="redirect"       />
		<result property="perms"          column="perms"          />
		<result property="icon"           column="icon"           />
		<result property="createBy"       column="create_by"      />
		<result property="createTime"     column="create_time"    />
		<result property="updateTime"     column="update_time"    />
		<result property="updateBy"       column="update_by"      />
		<result property="remark"         column="remark"         />
	</resultMap>

	<sql id="selectMenuVo">
        select menu_id, menu_name, parent_id, order_num, path, component, `query`, is_frame, is_cache, menu_type, visible, status, redirect, ifnull(perms,'') as perms, icon, create_time
		from sys_menu
    </sql>
    
    <select id="selectMenuList" parameterType="SysMenu" resultMap="SysMenuResult">
		<include refid="selectMenuVo"/>
		<where>
			<if test="menuName != null and menuName != ''">
				AND menu_name like concat('%', #{menuName}, '%')
			</if>
			<if test="visible != null and visible != ''">
				AND visible = #{visible}
			</if>
			<if test="status != null and status != ''">
				AND status = #{status}
			</if>
		</where>
		order by parent_id, order_num
	</select>
	
	<select id="selectMenuTreeAll" resultMap="SysMenuResult">
		select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.`query`, m.visible, m.status, m.redirect, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
		from sys_menu m where m.menu_type in ('M', 'C', 'N') and m.status = 0
		order by m.parent_id, m.order_num
	</select>
	
	<select id="selectMenuListByUserId" parameterType="SysMenu" resultMap="SysMenuResult">
		select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.`query`, m.visible, m.status, m.redirect, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
		from sys_menu m
		left join sys_role_menu rm on m.menu_id = rm.menu_id
		left join sys_user_role ur on rm.role_id = ur.role_id
		left join sys_role ro on ur.role_id = ro.role_id
		where ur.user_id = #{params.userId}
		<if test="menuName != null and menuName != ''">
            AND m.menu_name like concat('%', #{menuName}, '%')
		</if>
		<if test="visible != null and visible != ''">
            AND m.visible = #{visible}
		</if>
		<if test="status != null and status != ''">
            AND m.status = #{status}
		</if>
		order by m.parent_id, m.order_num
	</select>
    
    <select id="selectMenuTreeByUserId" parameterType="Long" resultMap="SysMenuResult">
		select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.`query`, m.visible, m.status, m.redirect, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
		from sys_menu m
			 left join sys_role_menu rm on m.menu_id = rm.menu_id
			 left join sys_user_role ur on rm.role_id = ur.role_id
			 left join sys_role ro on ur.role_id = ro.role_id
			 left join sys_user u on ur.user_id = u.user_id
		where u.user_id = #{userId} and m.menu_type in ('M', 'C', 'N') and m.status = 0  AND ro.status = 0
		order by m.parent_id, m.order_num
	</select>
	
	<select id="selectMenuListByRoleId" resultType="Long">
		select m.menu_id
		from sys_menu m
            left join sys_role_menu rm on m.menu_id = rm.menu_id
        where rm.role_id = #{roleId}
            <if test="menuCheckStrictly">
              and m.menu_id not in (select m.parent_id from sys_menu m inner join sys_role_menu rm on m.menu_id = rm.menu_id and rm.role_id = #{roleId})
            </if>
		order by m.parent_id, m.order_num
	</select>
	
	<select id="selectMenuPerms" resultType="String">
		select distinct m.perms
		from sys_menu m
			 left join sys_role_menu rm on m.menu_id = rm.menu_id
			 left join sys_user_role ur on rm.role_id = ur.role_id
	</select>

	<select id="selectMenuPermsByUserId" parameterType="Long" resultType="String">
		select distinct m.perms
		from sys_menu m
			 left join sys_role_menu rm on m.menu_id = rm.menu_id
			 left join sys_user_role ur on rm.role_id = ur.role_id
			 left join sys_role r on r.role_id = ur.role_id
		where m.status = '0' and r.status = '0' and ur.user_id = #{userId}
	</select>
	
	<select id="selectMenuPermsByRoleId" parameterType="Long" resultType="String">
		select distinct m.perms
		from sys_menu m
			 left join sys_role_menu rm on m.menu_id = rm.menu_id
		where m.status = '0' and rm.role_id = #{roleId}
	</select>
	
	<select id="selectMenuById" parameterType="Long" resultMap="SysMenuResult">
		<include refid="selectMenuVo"/>
		where menu_id = #{menuId}
	</select>
	
	<select id="hasChildByMenuId" resultType="Integer">
	    select count(1) from sys_menu where parent_id = #{menuId}  
	</select>
	
	<select id="checkMenuNameUnique" parameterType="SysMenu" resultMap="SysMenuResult">
		<include refid="selectMenuVo"/>
		where menu_name=#{menuName} and parent_id = #{parentId} limit 1
	</select>
	
	<update id="updateMenu" parameterType="SysMenu">
		update sys_menu
		<set>
			<if test="menuName != null and menuName != ''">menu_name = #{menuName},</if>
			<if test="parentId != null">parent_id = #{parentId},</if>
			<if test="orderNum != null">order_num = #{orderNum},</if>
			<if test="path != null and path != ''">path = #{path},</if>
			<if test="component != null">component = #{component},</if>
			<if test="query != null">`query` = #{query},</if>
			<if test="isFrame != null and isFrame != ''">is_frame = #{isFrame},</if>
			<if test="isCache != null and isCache != ''">is_cache = #{isCache},</if>
			<if test="menuType != null and menuType != ''">menu_type = #{menuType},</if>
			<if test="visible != null">visible = #{visible},</if>
			<if test="status != null">status = #{status},</if>
			<if test="redirect != null">redirect = #{redirect},</if>
			<if test="perms !=null">perms = #{perms},</if>
			<if test="icon !=null and icon != ''">icon = #{icon},</if>
			<if test="remark != null and remark != ''">remark = #{remark},</if>
			<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
			update_time = sysdate()
		</set>
		where menu_id = #{menuId}
	</update>

	<insert id="insertMenu" parameterType="SysMenu">
		insert into sys_menu(
		<if test="menuId != null and menuId != 0">menu_id,</if>
		<if test="parentId != null and parentId != 0">parent_id,</if>
		<if test="menuName != null and menuName != ''">menu_name,</if>
		<if test="orderNum != null">order_num,</if>
		<if test="path != null and path != ''">path,</if>
		<if test="component != null and component != ''">component,</if>
		<if test="query != null and query != ''">`query`,</if>
		<if test="isFrame != null and isFrame != ''">is_frame,</if>
		<if test="isCache != null and isCache != ''">is_cache,</if>
		<if test="menuType != null and menuType != ''">menu_type,</if>
		<if test="visible != null">visible,</if>
		<if test="status != null">status,</if>
		<if test="redirect != null">redirect,</if>
		<if test="perms !=null and perms != ''">perms,</if>
		<if test="icon != null and icon != ''">icon,</if>
		<if test="remark != null and remark != ''">remark,</if>
		<if test="createBy != null and createBy != ''">create_by,</if>
		create_time
		)values(
		<if test="menuId != null and menuId != 0">#{menuId},</if>
		<if test="parentId != null and parentId != 0">#{parentId},</if>
		<if test="menuName != null and menuName != ''">#{menuName},</if>
		<if test="orderNum != null">#{orderNum},</if>
		<if test="path != null and path != ''">#{path},</if>
		<if test="component != null and component != ''">#{component},</if>
		<if test="query != null and query != ''">#{query},</if>
		<if test="isFrame != null and isFrame != ''">#{isFrame},</if>
		<if test="isCache != null and isCache != ''">#{isCache},</if>
		<if test="menuType != null and menuType != ''">#{menuType},</if>
		<if test="visible != null">#{visible},</if>
		<if test="status != null">#{status},</if>
		<if test="redirect != null">#{redirect},</if>
		<if test="perms !=null and perms != ''">#{perms},</if>
		<if test="icon != null and icon != ''">#{icon},</if>
		<if test="remark != null and remark != ''">#{remark},</if>
		<if test="createBy != null and createBy != ''">#{createBy},</if>
		sysdate()
		)
	</insert>
	
	<delete id="deleteMenuById" parameterType="Long">
	    delete from sys_menu where menu_id = #{menuId}
	</delete>

</mapper> 
  1. SysMenu.java添加字段 redirect
	/** 路由重定向 */
    private String redirect;
	
	public String getRedirect() {
        return redirect;
    }

    public void setRedirect(String redirect) {
        this.redirect = redirect;
    }
  1. SysMenuServiceImpl.java添加方法获取路由重定向信息,SysMenuService.java也要实现对应接口
	/**
     * 获取路由名称
     *
     * @param menu 菜单信息
     * @return 路由名称
     */
    public String getRouteRedirect(SysMenu menu)
    {
        return menu.getRedirect();
    }

前端

  1. 改造menu/index.vue
		  <el-col :span="24">
            <el-form-item label="菜单类型" prop="menuType">
              <el-radio-group v-model="form.menuType">
                <el-radio label="M">目录</el-radio>
                <el-radio label="C">菜单</el-radio>
                <el-radio label="F">按钮</el-radio>
                <el-radio label="N">嵌套路由菜单</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
          .....
		  <el-col :span="12" v-if="'CN'.includes(form.menuType)">
            <el-form-item prop="component">
              <span slot="label">
                <el-tooltip content="访问的组件路径,如:`system/user/index`,默认在`views`目录下" placement="top">
                <i class="el-icon-question"></i>
                </el-tooltip>
                组件路径
              </span>
              <el-input v-model="form.component" placeholder="请输入组件路径" />
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.menuType != 'M'">
            <el-form-item prop="perms">
              <el-input v-model="form.perms" placeholder="请输入权限标识" maxlength="100" />
              <span slot="label">
                <el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasPermi('system:user:list')`)" placement="top">
                <i class="el-icon-question"></i>
                </el-tooltip>
                权限字符
              </span>
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="'CN'.includes(form.menuType)">
            <el-form-item prop="query">
              <el-input v-model="form.query" placeholder="请输入路由参数" maxlength="255" />
              <span slot="label">
                <el-tooltip content='访问路由的默认传递参数,如:`{"id": 1, "name": "ry"}`' placement="top">
                <i class="el-icon-question"></i>
                </el-tooltip>
                路由参数
              </span>
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="'N'.includes(form.menuType)">
            <el-form-item prop="redirect">
              <el-input v-model="form.redirect" placeholder="请输入重定向地址" maxlength="255" />
              <span slot="label">
                <el-tooltip content='路由的重定向地址,如:`/device/list/base`' placement="top">
                <i class="el-icon-question"></i>
                </el-tooltip>
                默认定向
              </span>
            </el-form-item>
          </el-col>
  1. 改造layout/component/TagsView/index.vue的部分方法
    isActive(route) {
      let path = this.$route.path;
      if (this.$route.meta.nested) {
          path = this.$route.matched[1].path;
      }
      return route.path === path;
    },
    addTags() {
      const { name, meta } = this.$route
      if (meta.nested) {
        this.$store.dispatch(
            "tagsView/addView",
            this.$route.matched[1]
        );
        return false;
      }
      if (name) {
        this.$store.dispatch('tagsView/addView', this.$route)
        if (this.$route.meta.link) {
          this.$store.dispatch('tagsView/addIframeView', this.$route)
        }
      }
      return false
    },
	toLastView(visitedViews, view) {
	   const latestView = visitedViews.slice(-1)[0]
	   if (latestView) {
	     this.$router.push(latestView.fullPath || latestView.path)
	   } else {
	     // now the default is to redirect to the home page if there is no tags-view,
	     // you can adjust it according to your needs.
	     if (view.name === 'Dashboard') {
	       // to reload home page
	       this.$router.replace({ path: '/redirect' + view.fullPath })
	     } else {
	       this.$router.push('/')
	     }
	   }
	 },
  
  1. 改造layout/component/AppMain.vue 的router-view,把:key="key"删了,不然跳转子路由还是会刷新父路由
<router-view v-if="!$route.meta.link" />

使用示例

菜单结构如下:

在这里插入图片描述

我要在设备目录中实现嵌套路由,默认定向填第一个子路由,菜单类型选嵌套路由菜单,组件路径选择含有router-link 标签的父路由组件,如下图

在这里插入图片描述

子路由第一个路由显示打开,其他的路由显示关闭,组件路径选择子组件路径,路由地址会自动转换成路由的name,会把第一个字母变成大写的,跳转的时候用name跳转的话,如下图所示,{name:RealTime}

在这里插入图片描述

完毕

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值