JSTL(JSP Standard Tag Library,JSP标准标签库)是一个不断完善的开放源代码的JSP标签库。

JSTL 核心标签库标签共有13个,功能上分为4类:

1.表达式控制标签:out、set、remove、catch

2.流程控制标签:if、choose、when、otherwise

3.循环标签:forEach、forTokens

4.URL操作标签:import、url、redirect

使用时需要在项目中加入jstl-1.2.jar,同时在jsp中加入以下代码来使用

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

只使用 核心标签库标签中的标签是不能满足需求的,常常会需要自定义标签。

一、新建.tld文件

.tld文件需要放在WEB-INF的tld文件夹下,没有则需要新建。否则tomcat读不到

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
                        "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
    <tlib-version>1.0</tlib-version>
    <jsp-version>1.2</jsp-version>
    <!-- <short-name>这个标签是指定我们定义标签的简称,这个作用不大 -->
    <short-name>t</short-name>
    <!-- <uri>是给这个标签文件指定一个访问路径,这个路径我们在Jsp页面中引入这个标签的时候需要用到 ,如:<%@ taglib prefix="t" 
        uri="/mytags"%> -->
    <uri>/mytags</uri>
    <display-name>"自定义标签"</display-name>

    <!-- 菜单生成控件 -->
    <tag>
        <name>menu</name>
        <!-- <tag-class>这个标签就是指定我们自定义的标签类的全称 -->
        <tag-class>com.zhs.tag.MenuTag</tag-class>
        <!-- <body-content>这个标签表明自定义标签是否有标签体内容(empty:没有,JSP:有) -->
        <body-content>JSP</body-content>
        <display-name>左侧菜单生成控件</display-name>
        <small-icon>111</small-icon>
        <description>左侧菜单生成控件可选样式easyui,bootstrap,json</description>
<!--         参数,后台可根据name属性取出值 -->
        <attribute>
            <name>menuFun</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
            <description>菜单信息</description>
        </attribute>
        <attribute>
            <name>style</name>
            <rtexprvalue>true</rtexprvalue>
            <description>菜单样式</description>
        </attribute>
    </tag>
    
</taglib>

二、新建java类处理标签中的数据(可将数据装换成任何需要的样式)

import java.io.IOException;
import java.util.List;
import java.util.Map;
import javax.servlet.jsp.JspTagException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;
import com.zhs.model.TSFunction;
/**
 * 
 * 类描述:菜单标签*/
public class MenuTag extends TagSupport {
    private static final long serialVersionUID = 1L;
    protected String style = "easyui";// 菜单样式
    protected List<Map> menuFun;// 一级菜单
    // 1、public void setPageContext(PageContext pc),
    // JSP引擎实例化标签处理器后,将调用setPageContext方法将JSP页面的pageContext对象传递给标签处理器,标签处理器以后可以通过这个pageContext对象与JSP页面进行通信。
    // 2、public void setParent(Tag
    // t),setPageContext方法执行完后,WEB容器接着调用的setParent方法将当前标签的父标签传递给当前标签处理器,如果当前标签没有父标签,则传递给setParent方法的参数值为null。
    // 3、public int
    // doStartTag(),调用了setPageContext方法和setParent方法之后,WEB容器执行到自定义标签的开始标记时,就会调用标签处理器的doStartTag方法。
    // 4、public int
    // doEndTag(),WEB容器执行完自定义标签的标签体后,就会接着去执行自定义标签的结束标记,此时,WEB容器会去调用标签处理器的doEndTag方法。
    // 5、public void
    // release(),通常WEB容器执行完自定义标签后,标签处理器会驻留在内存中,为其它请求服务器,直至停止web应用时,web容器才会调用release方法。

    @Override
    public int doStartTag() throws JspTagException {
//        返回值类型:
//        SKIP_BODY(=0) :跳过了开始和结束标签之间的代码。
//        EVAL_BODY_INCLUDE(=1):将body的内容输出到存在的输出流中
//        SKIP_PAGE(=5) : 忽略剩下的页面。
//        EVAL_PAGE(=6):继续执行下面的页
        return EVAL_PAGE;
    }

    @Override
    public int doEndTag() throws JspTagException {
        try {
            JspWriter out = this.pageContext.getOut();
            String menu = (String) this.pageContext.getSession().getAttribute(
                    "leftMenuCache" + style);
            if (menu != null) {
                //向页面转发数据(本例中为列表)
                out.print(menu);
            } else {
                menu = end().toString();
                this.pageContext.getSession().setAttribute(
                        "leftMenuCache" + style, menu);
                out.print(menu);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
        return EVAL_PAGE;
    }
    public StringBuffer end() {
        StringBuffer sb = new StringBuffer();
        sb.append(getAceMultistageTree(menuFun));
        return sb;
    }
    //获取til文件中的值
    public void setStyle(String style) {
        this.style = style;
    }
    public void setMenuFun(List<Map> menuFun) {
        this.menuFun = menuFun;
    }
    //处理数据
    public static String getAceMultistageTree(List<Map> list) {
        StringBuffer menuString = new StringBuffer();
        int curIndex = 0;
        for (Map map : list) {
            TSFunction parent=(TSFunction)map.get("parentfunction");
            List<TSFunction> childList=(List<TSFunction>)map.get("childfunction");
            if(childList==null){
                menuString.append("<li class='active'>"
                        +"<a href='index.html'>"
                        +"<i class='menu-icon fa fa-tachometer'></i>"
                        +"<span class='menu-text'> "
                        +parent.getFunctionName()                    
                        +" </span>"
                        +"</a>"
                        +"<b class='arrow'></b>"
                        +"</li>");
            }else{
                menuString.append("<li class=''>"
                        +"<a href='#' class='dropdown-toggle'>"
                        +"<i class='menu-icon fa fa-leaf green'></i>"
                        +"<span class='menu-text'> "
                        +parent.getFunctionName()                        
                        +" </span>"
                        +"<b class='arrow fa fa-angle-down'></b>"
                        +"</a>"
                        +"<b class='arrow'></b>"
                        +"<ul class='submenu'>");
                for(TSFunction child:childList){
                    menuString.append("<li class=''>"
                            +"<a  href=\"javascript:loadModule('"
                            +child.getFunctionName()    
                            +"','/cssiot"
                            +child.getFunctionUrl()
                            +"')\">"
                            +"<i class='menu-icon fa fa-caret-right'></i>"
                            +child.getFunctionName()
                            +"</a>"
                            +"<b class='arrow'></b>"
                            +"</li>");
                }
                menuString.append("</ul></li>");
            }
        }
        return menuString.toString();
    }
}

注:

TagSupport 对象可以引用tomcat中的jsp-api.jar与servlet-api.jar

三、在jsp页面中使用

<t:menu menuFun="${menuMap}"  style="ace" ></t:menu>

使用时可向后台传递参数,整个过程(tld文件,jsp文件,java文件)中参数名要保持一致

 

附录:

程序用的实体类

import java.util.List;
import java.util.Map;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

/**
 * 菜单权限表
 * 
 */
@Entity
@Table(name = "t_s_function")
@org.hibernate.annotations.Proxy(lazy = false)
public class TSFunction extends BaseEntity {
    private TSFunction TSFunction;// 父菜单
    private String functionName;// 菜单名称
    private Short functionLevel;// 菜单等级
    private String functionUrl;// 菜单地址
    private String functionOrder;// 菜单排序
    private String iconId;// 图标id
    
    public boolean hasSubFunction(Map<Integer, List<TSFunction>> map) {
        if (map.containsKey(this.getFunctionLevel() + 1)) {
            return hasSubFunction(map.get(this.getFunctionLevel() + 1));
        }
        return false;
    }

    public boolean hasSubFunction(List<TSFunction> functions) {
        for (TSFunction f : functions) {
            if (f.getTSFunction().getId().equals(this.getId())) {
                return true;
            }
        }
        return false;
    }

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "parentfunctionid")
    public TSFunction getTSFunction() {
        return this.TSFunction;
    }

    public void setTSFunction(TSFunction TSFunction) {
        this.TSFunction = TSFunction;
    }

    @Column(name = "functionname", nullable = false, length = 50)
    public String getFunctionName() {
        return this.functionName;
    }

    public void setFunctionName(String functionName) {
        this.functionName = functionName;
    }

    @Column(name = "functionlevel")
    public Short getFunctionLevel() {
        return this.functionLevel;
    }

    public void setFunctionLevel(Short functionLevel) {
        this.functionLevel = functionLevel;
    }

    @Column(name = "functionurl", length = 100)
    public String getFunctionUrl() {
        return this.functionUrl;
    }

    public void setFunctionUrl(String functionUrl) {
        this.functionUrl = functionUrl;
    }

    @Column(name = "functionorder")
    public String getFunctionOrder() {
        return functionOrder;
    }

    public void setFunctionOrder(String functionOrder) {
        this.functionOrder = functionOrder;
    }

    public String getIconId() {
        return iconId;
    }

    public void setIconId(String iconId) {
        this.iconId = iconId;
    }
}