在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. poj3693

    //Accepted 12004 KB 407 ms /* source:poj3693 time :20150819 by :songt */ /*题解: 搞了一天,总算弄完了 首先,我们来明确一个 ...

  2. Ubuntu下libpcap安装

    1.首先按下面的博客教程下载和安装四个软件包: 点击打开链接 2.这四个软件都安装好之后按下面教程新建Makefile文件和test.c文件: 点击打开链接 Makefie: all: test.c ...

  3. 六大免费网站数据采集器对比(火车头,海纳,云采集,ET,三人行,狂人采集)

    2013年02月27日 PHP开源系统 暂无评论 阅读 497 views 次 在目前的站长圈内,比较流行的采集工具有很多,但是总结起来,比较出名的免费的就这么几个:火车头,海纳,云采集,ET,三人行 ...

  4. 基于ReentrantLock的AQS的源码分析(独占、非中断、不超时部分)

    刚刚看完了并发实践这本书,算是理论具备了,看到了AQS的介绍,再看看源码,发现要想把并发理解透还是很难得,花了几个小时细分析了一下把可能出现的场景尽可能的往代码中去套,还是有些收获,但是真的很费脑,还 ...

  5. 黑马程序员——【Java高新技术】——案例:交通灯管理系统

    ---------- android培训.java培训.期待与您交流! ---------- 一.交通灯管理系统的项目需求 Ø 异步随机生成按照各个路线行驶的车辆 例如: 由南向而来去往北向的车辆 - ...

  6. 转的: 重绘ListView 修改标题颜色

    1.owerDraw 设置为true 2.实现事件 DrawColumnHeader DrawItem DrawSubItem private void listView1_DrawColumnHea ...

  7. 【转】JavaScript 风格指南/编码规范(Airbnb公司版)

    原文转自:http://blog.jobbole.com/79484/ Airbnb 是一家位于美国旧金山的公司,本文是其内部的 JavaScript 风格指南/编码规范,在 Github 上有 11 ...

  8. /date(-62135596800000)转换正常格式的时间

    function formatDatebox(value) { if (value == null || value == '') { return ''; } var dt = parseToDat ...

  9. day04关于MySqL—Android小白的学习笔记

    Mysql入门 1. 数据库基本知识(了解) 1.1.数据库介绍 1.1.1.什么是数据库?数据库的作用是什么? 数据库就是存储数据的仓库,其本质是一个文件系统,数据按照特定的格式将数据存储起来,用户 ...

  10. MCMC: The Metropolis-Hastings Sampler

    本文主要译自:MCMC:The Metropolis-Hastings Sampler 上一篇文章中,我们讨论了Metropolis 采样算法是如何利用马尔可夫链从一个复杂的,或未归一化的目标概率分布 ...