天天看点

Thymeleaf+MySQL实现一个两级树状目录首页导航栏Thymeleaf+MySQL实现一个两级树状目录首页导航栏

Thymeleaf+MySQL实现一个两级树状目录首页导航栏

在完成个人毕设的过程中,依旧使用的是对用户权限判断,分别定制独立页面的方式,这样大大增加了前端的页面冗余,还使工作量大大提升,后来通过朋友提示,可以通过数据库来读取每个用户的个人主页设置。再结合正在使用的Thymeleaf,因为不会js,因此打算全部通过Thymeleaf来实现此功能

思路步骤

我的项目环境包括前端的layui和Thymeleaf,后端则是用的SpringBoot的网页框架。

  1. 数据库的实体类entity
    public class Menu {
         private int access;             //权限
         private String menuid;          //每项菜单的ID
         private String menuname;        //每项菜单的名称
         private String location;        //菜单所处左侧导航还是顶部ToolBar
         private String menutype;        //菜单类型,区分子菜单归属的上一级父菜单
         private String menulevel;       //菜单等级,区分父菜单还是子菜单
         private String url;             //菜单跳转URL
         private List<Menu> secondMenus; //二级目录集合List
     }
               
    因为后面的实现过程中发现,若没有List实现父包子菜单集合的属性,会使得在循环时没办法实现父菜单点击收回子菜单的功能,这个后面仍会说明。
  2. 实现此服务层功能@Service类
    @Override
     public List<Menu> getCorrectMenusByID(int userid) {
         //由于数据库使用的是平面设计 没有进行分层 因此在另外定义了一个没有注入使用SQL语句的Service方法
         //然后通过此方法调用其他SQL然后对menus对象初始化 把二级菜单List填充
         //MenuUtil定义了用于区分菜单等级的常量字段
         List<Menu> menus = mapper.getMenusByIDMenuLv(userid, MenuUtil.MENU_LEVEL_ONE);
         for(Menu m: menus){
             m.setSecondMenus(mapper.getMenusByID_Lv_Type(userid, MenuUtil.MENU_LEVEL_TWO, m.getMenutype()));
         }
         return menus;
     }
               
  3. 响应请求@Controller类
    @RequestMapping(value = {"index", "index.html"})
     public String indexPage(Model m, HttpServletRequest request){
         //从session取User对象
         HttpSession session = request.getSession();
         User current = (User) session.getAttribute(UserUtil.CURRENT_USER);  
         //给Thymeleaf填充项设置属性
         m.addAttribute("name", userInfo.getNickname());
         m.addAttribute(MenuUtil.USER_MENUS, setSessionMenus(current, session));
         return "index";
     }
     public List<Menu> setSessionMenus(User user, HttpSession session){
         //获取已分级的新菜单
         List<Menu> menusNew = menuService.getCorrectMenusByID(user.getId());   
         session.setAttribute(MenuUtil.USER_MENUS, menusNew);
         return menusNew;
     }
               
  4. 前端Html结构
    <ul class="layui-nav layui-nav-tree" lay-filter="test">
         <li class="layui-nav-item layui-nav-itemed" th:each="menu:${userMenus}">
             <a href="javascript:;"
                 th:text="${menu.menuname}">父菜单</a>
             <dl class="layui-nav-child">
                 <dd th:each="child:${menu.secondMenus}">
                     <a href="javascript:;"
                         th:text="${child.menuname}">子菜单</a>
                 </dd>
             </dl>
         </li>
     </ul>
               

    此结构是使用我参考的别的项目的菜单结构修改的,可以有更简表达形式,此处不再做修改。

    若此处不是使用父子菜单包含而是使用的平级循环,通过一个

    th:each

    th:if

    会导致子菜单也是独立项,没办法实现父菜单的收回子菜单的功能,因为这个js是已经写在layui模板中的模块。
    <!-- 错误示范 -->
     <ul class="layui-nav layui-nav-tree" lay-filter="test">
         <li class="layui-nav-item layui-nav-itemed" th:each="menu:${userMenus}">
             <a href="javascript:;"
                 th:if="${menu.menulevel} eq 1"
                 th:text="${menu.menuname}">父菜单</a>
             <dl class="layui-nav-child">
                 <dd><a href="javascript:;"
                         th:if="${menu.menulevel} eq 2"
                         th:text="${menu.menuname}">子菜单</a>
                 </dd>
             </dl>
         </li>
     </ul>
     <!-- 错误示范 -->
               

错误总结

  1. Thymeleaf的

    th:each

    循环需要写在内层,否则会导致每个item都是独立的大框架,没办法做到单选响应的css样式
  2. 子菜单循环时写的应该是

    ${menu.secondMenus}

    而不是

    ${userMenus.secondMenus}

    ,userMenus是个List,没有secondMenus属性会导致

    EL1008E

    报错
  3. 此处也能通过Thymeleaf直接读取Session而非通过传值的方法得到MenusList
  4. 注意写Mapper、Service和其实现类时的规范

参考文献

  1. thymeleaf之菜单树
  2. springboot+thymeleaf把菜单栏存放到数据库
  3. 关于springMVC结合mybatis,thymeleaf,实现二级联动