在WEB开发中经常需要进行树形菜单的展示,本例通过不同角度的总结了如下三种实现方式:

  1. 通过JS的递归实现前端菜单DOM的动态创建
  2. 通过JSP的include指令结合JSTL表达式语言递归实现菜单的展示
  3. 通过扩展JSP的标签在后端实现菜单的DOM节点并响应给前端展示

针对第一种方法,可以采用JS的相关组件,或者使用JS的递归调用将服务端相应的数据组装成DOM节点内容,动态添加到菜单的Container中,网上的例子较多,在此不再赘述,本例就后两种方案进行讲解。

通过JSP的include指令结合JSTL表达式语言递归实现菜单的展示

由于JSP中的JSTL不支持递归,又不想在JSP中加入Java脚本,可以采用JSP动态包含的方式组装菜单,当前方案需要服务端将菜单列表组装成树形结构,具体算法如下:

主页面menu.jsp

 <ul class="nav nav-list">
<c:if test="${not empty sessionScope.SESSION_MENUS}">
<c:forEach items="${sessionScope.SESSION_MENUS }" var="menu">
<%@include file="recursiveMenu.jsp"%>
</c:forEach>
</c:if>
</ul><!-- /.nav-list -->

递归调用页面recursiveMenu.jsp

 <%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<li>
<c:choose>
<c:when test="${empty menu.children }">
<a href="${menu.url }">
<i class="${menu.icon }"></i>
<span class="menu-text"> ${menu.name } </span>
</a>
</c:when>
<c:otherwise>
<a href="javascript:void(0);" class="dropdown-toggle">
<i class="${menu.icon }"></i>
<span class="menu-text"> ${menu.name } </span>
<b class="arrow icon-angle-down"></b>
<ul class="submenu">
<c:forEach items="${menu.children }" var="menu">
<c:set var="menu" value="${menu}" scope="request"/>
<jsp:include page="recursiveMenu.jsp"/>
</c:forEach>
</ul>
</a>
</c:otherwise>
</c:choose>
</li>

通过扩展JSP的标签在后端实现菜单的DOM节点并相应给前端展示

当前方案采用扩展JSP标签的方式实现具体实现方法如下

1、新建标签实现类MenuTa.java

 package com.luwei.console.mg.tag;

 import java.io.IOException;
import java.util.List; import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport; import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import com.luwei.console.mg.constant.KeyConst;
import com.luwei.console.mg.entity.ext.MenuExt; /**
* <Description> 菜单标签<br>
*
* @author lu.wei<br>
* @email 1025742048@qq.com <br>
* @date 2016年12月25日 <br>
* @since V1.0<br>
* @see com.luwei.console.mg.tag <br>
*/
public class MenuTag extends TagSupport {
private Logger logger = LoggerFactory.getLogger(this.getClass()); /**
* serialVersionUID <br>
*/
private static final long serialVersionUID = -2755997672501044414L; @SuppressWarnings("unchecked")
@Override
public int doStartTag() throws JspException {
Object menusObj = pageContext.getSession().getAttribute(KeyConst.KEY_SESSION_MENUS);
if (null != menusObj) {
List<MenuExt> menus = (List<MenuExt>) menusObj;
String menuStr = assumbleMenuHtml(menus);
try {
pageContext.getOut().println(menuStr);
}
catch (IOException e) {
logger.error("菜单标签创建菜单出错:{} ", e.getMessage(), e);
}
}
return super.doStartTag();
} /**
* <Description> TODO<br>
*
* @author lu.wei<br>
* @email 1025742048@qq.com <br>
* @date 2016年12月25日 上午9:29:26 <br>
* @param menus
* @return <br>
*/
private String assumbleMenuHtml(List<MenuExt> menus) {
StringBuffer sb = new StringBuffer(""); if (!menus.isEmpty()) {
long activeMenuId = 1;
Object avtiveMenuIdObj = pageContext.getSession().getAttribute(KeyConst.SESSION_ACTIVE_MENU_ID);
if (null != avtiveMenuIdObj) {
activeMenuId = (Long) avtiveMenuIdObj;
}
for (MenuExt menu : menus) { if (menu.getId() == activeMenuId) {
sb.append("<li class='active'>");
}
else {
sb.append("<li>");
} boolean hasChild = false;
if (null != menu.getChildren() && !menu.getChildren().isEmpty()) {
hasChild = true;
}
if (hasChild) {
sb.append("<a href='#' class='dropdown-toggle'> ");
}
else {
String url = menu.getUrl();
if (StringUtils.isNotEmpty(url)) {
if (url.contains("?")) {
url = (url + "&mid=" + menu.getId());
}
else {
url = (url + "?mid=" + menu.getId());
}
}
sb.append("<a href='").append(url).append("'>");
} if (StringUtils.isNotEmpty(menu.getIcon())) {
sb.append("<i class='").append(menu.getIcon()).append("'></i>");
}
sb.append("<span class='menu-text'>").append(menu.getName()).append("</span>");
if (hasChild) {
sb.append("<b class='arrow icon-angle-down'></b>");
}
sb.append("</a>");
if (hasChild) {
sb.append("<ul class='submenu'>").append(assumbleMenuHtml(menu.getChildren())).append("</ul>");
}
sb.append("</li>");
}
}
return sb.toString();
}
}

2、配置标签

在项目的WEB-INFO目录下新建文件treeMenuAssum.tld

 <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
" http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.2</jspversion>
<shortname>menu</shortname>
<uri>http://www.luwei.com/web/ext/menus</uri>
<tag>
<name>menu</name>
<tagclass>com.luwei.console.mg.tag.MenuTag</tagclass>
</tag>
</taglib>

3、使用菜单标签

在JSP页面中直接使用新建标签

<%@ taglib prefix="menu" uri="http://www.luwei.com/web/ext/menus" %>
<menu:menu/>

总结

  以上三种方式均能够实现后端服务的配置管理的无限树形菜单在前端显示出来,第一种方法服务端只需要将数据组装成前端需要的格式相应给前端,前端通过空间或者递归的方式动态创建DOM节点就可以了;二后两种方式采用纯Java相关的知识完全由服务端生成树形菜单,服务端会有一定的负载,同时采用JSP动态包含的方式,如果是在菜单中存在复杂逻辑的话不容易实现,因此推荐使用第一和第三中方案。

  具体采用哪种方式可以根据各自项目进行选择,但是实现原理都是相同的。

  

  

  

WEB开发中前后台树形菜单的展示设计的更多相关文章

  1. web开发中前后端传值

    在JavaScript中,页面与页面间的传值需要注意. 比如,我们通过url向下个页面进行传一个数字时,到下个页面进行解析出来后可能是一个字符串.这样会导致一个现象.调试时,发现我要传的值的确传过来了 ...

  2. web 开发之酷炫--- 酷炫展示

    http://www.cnblogs.com/dsxniubility/p/4588560.html

  3. java web开发_购物车功能实现

    java web开发_购物车功能实现 之前没有接触过购物车的东东,也不知道购物车应该怎么做,所以在查询了很多资料,总结一下购物车的功能实现. 查询的资料,找到三种方法: 1.用cookie实现购物车: ...

  4. 简明易懂,将细节隐藏,面向新手树立web开发概念——学完Java基础语法,超快速上手springboot+mybatiJavaWeb开发

    简明易懂,将细节隐藏,面向新手树立web开发概念 --学完Java基础语法,超快速上手JavaWeb开发 Web本质(先忽视各种协议) Web应用可以理解为浏览器和服务器之间的交互. 我们可以看一个简 ...

  5. Asp.Net Web API开发微信后台

    如果说用Asp.Net开发微信后台是非主流,那么Asp.Net Web API的微信后台绝对是不走寻常路. 需要说明的是,本人认为Asp.Net Web API在开发很多不同的请求方法的Restful ...

  6. C++后台实践:古老的CGI与Web开发

    本文写给C/C++程序猿,也适合其他对历史感兴趣的程序猿 ============================================= 谈到web开发,大家首先想到的PHP.JavaEE ...

  7. 渐进式web应用开发-- 使用后台同步保证离线功能(六)

    _ 阅读目录 一:什么是后台同步保证离线功能呢? 二:后台同步是如何实现的呢? 三:如何给sync事件传递数据? 四:在我们的项目中添加后台同步功能 回到顶部 一:什么是后台同步保证离线功能呢? 在我 ...

  8. 使用ztree展示树形菜单结构

    官网:http://www.treejs.cn/v3/main.php#_zTreeInfo 一.功能简介 在权限系统中,实现给角色指定菜单权限的功能.主要包括以下几点: 读取全部菜单项,并以树形结构 ...

  9. java web 开发三剑客 -------电子书

    Internet,人们通常称为因特网,是当今世界上覆盖面最大和应用最广泛的网络.根据英语构词法,Internet是Inter + net,Inter-作为前缀在英语中表示“在一起,交互”,由此可知In ...

随机推荐

  1. jquery自定义插件——以 选项卡插件为例

    一直打算尝试自定义插件,终于付诸实践了,现在把内容发表出来,与大家共勉. 我是根据自己正在用的插件,模仿其源码,实现的自定义插件,完成之后,在网上看相关资料,对自定义插件部分,有了更明确的认识. jq ...

  2. Struts2 配置文件result的name属性和type属性

    Struts2 配置文件result的name属性和type属性:Name属性SUCCESS:Action正确的执行完成,返回相应的视图,success是 name属性的默认值: NONE:表示Act ...

  3. (zhuan)Python 虚拟环境:Virtualenv

    Python 虚拟环境:Virtualenv zhuanzi: http://liuzhijun.iteye.com/blog/1872241 virtualenv virtualenv用于创建独立的 ...

  4. github上下载的文件如何在本地运行

    最近想学习自己写插件,所以先下载大神写的插件膜拜下,下载下来以后,直接双击运行报错,大神怎么会犯这么低级的错误咧!所以在网上查资料,找到了解决方法. (1)上传到github上面的插件都很规范,文件根 ...

  5. nginx 之 grok 过滤

    简介   前面我们的nginx日志编码使用的json,logstash直接输入预定义好的 JSON 数据,这样就可以省略掉 filter/grok 配置,但是在我们的生产环境中,日志格式往往使用的是普 ...

  6. PHP易混淆函数的区分方法及意义

    1.echo和print的区别   PHP中echo和print的功能基本相同(输出),但是两者之间还是有细微差别的.echo输出后没有返回值,但print有返回值,当其执行失败时返回flase.因此 ...

  7. linux学习笔记2-linux的常用命令

    第一篇博客:linux学习笔记1-ubuntu的安装与基本设置 之中,已经介绍了如何安装linux操作系统,以及一些基本的设置修改. 本篇博客主要介绍linux中的一些常用的终端命令 ======== ...

  8. github中redme添加图片

    README文件后缀名为md.md是markdown的缩写,markdown是一种编辑博客的语言.格式如下: ![](img_url) 即 叹号! + 方括号[ ] + 括号( ) 其中叹号里是图片的 ...

  9. linux 关机要点

    主要围绕 sync shutdown reboot这几个指令 将数据同步写入硬盘中的挃令: sync:关机前要保存进硬盘.事实上sync也可以被一般账号使用喔!只丌过一般账号用户所更新的硬盘数据就仅有 ...

  10. Linux系统重启python程序

    #! /usr/bin/env python #coding=utf-8 import sys import ConfigParser import urllib import urllib2 fro ...