Overview
本文针对以JSP为主的前端界面,如何展示数据以及接收后台传输的数据做出了一点说明。
目前框架前端页面所使用到的标签,主要为三种:普通的JSP标签,JSP标准标签库(JSTL),标签库描述符。下面分别介绍这三种不同的形式,并以框架中的src/main/webapp/WEB-INF/views/modules/sys
文件夹中的后台管理主页面sysIndex.jsp
为例进行分析。
JSP标签
普通的JSP标签几乎是在HTML标签之外,添加了一些传输数据和控制显示的功能,在此不再做过多的解释。请参考以下网址详细了解:http://www.w3cschool.cc/jsp
JSP标准标签库(JSTL)
JSP标准标签库(JSTL)是一个JSP标签集合,它封装了JSP应用的通用核心功能。
JSTL支持通用的、结构化的任务,比如迭代,条件判断,XML文档操作,国际化标签,SQL标签。 除了这些,它还提供了一个框架来使用集成JSTL的自定义标签。
JSTL标签按照功能可以分为核心标签,格式化标签,SQL 标签,XML标签,JSTL函数。
根据我们的需求,这里只介绍一下核心标签,并省略了JSTL库的安装。
核心标签是最常用的JSTL标签。引用核心标签库的语法如下:
1 2 3 4 | <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> |
- <c:out> 用于在JSP中显示数据,就像<%= ... >
- <c:set> 用于保存数据
- <c:remove> 用于删除数据
- <c:catch> 用来处理产生错误的异常状况,并且将错误信息储存起来
- <c:if> 与我们在一般程序中用的if一样
- <c:choose> 本身只当做<c:when>和<c:otherwise>的父标签
- <c:when> <c:choose>的子标签,用来判断条件是否成立
- <c:otherwise> <c:choose>的子标签,接在<c:when>标签后,当<c:when>标签判断为false时被执行
- <c:import> 检索一个绝对或相对 URL,然后将其内容暴露给页面
- <c:forEach> 基础迭代标签,接受多种集合类型
- <c:forTokens> 根据指定的分隔符来分隔内容并迭代输出
- <c:param> 用来给包含或重定向的页面传递参数
- <c:redirect> 重定向至一个新的URL.
- <c:url> 使用可选的查询参数来创造一个URL
以<c:forEach>为例,对该标签详细说明:
<c:forEach>标签封装了Java中的for,while,do-while循环。它迭代一个集合中的对象。
属性
<c:forEach>标签有如下属性:
属性 | 描述
- items 要被循环的信息
- begin 开始的元素(0=第一个元素,1=第二个元素)
- end 最后一个元素(0=第一个元素,1=第二个元素)
- step 每一次迭代的步长
- var 代表当前条目的变量名称
- varStatus 代表循环状态的变量名称
该标签主要用来在JSP页面中循环显示一个列表型栏目,比如从后台取到一个用户list数据,使用此标签可以循环将用户list中的每一个用户信息显示在JSP页面。
<c:forEach>实例演示
1 2 3 4 5 6 7 8 9 10 11 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <html> <head> <title>c:forEach 标签实例</title> </head> <body> <c:forEach var="i" begin="1" end="5"> Item <c:out value="${i}"/><p> </c:forEach> </body> </html> |
结果显示如下:
1 2 3 4 5 | Item 1 Item 2 Item 3 Item 4 Item 5 |
关于所有这些标签的更详细信息,请参见:http://www.w3cschool.cc/jsp/jsp-jstl.html
标签库描述符
tld是taglib description 的缩写。
标签库描述文件,如要在JSP页面中实现JSP标签,必须首先定义实现标签的类,然后在标签库描述文件(TLD)中将写好的类映射成jsp标签,最后在JSP文件中使用定义好的标签,就可以生成动态的JSP内容。
下面结合sysIndex.jsp
完整说明整个流程。
1 2 3 4 5 6 7 | sysIndex.jsp代码片段: <%@ page contentType="text/html;charset=UTF-8" %> <%@ include file="/WEB-INF/views/include/taglib.jsp"%> <html> <head> ... |
<%@ include file="/WEB-INF/views/include/taglib.jsp"%>
此代码将taglib.jsp
中的内容完整引入到sysIndex.jsp
中,先看一下taglib.jsp
中的代码:
1 2 3 4 5 6 7 8 9 10 | <%@ taglib prefix="shiro" uri="/WEB-INF/tlds/shiros.tld" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <%@ taglib prefix="fns" uri="/WEB-INF/tlds/fns.tld" %> <%@ taglib prefix="fnc" uri="/WEB-INF/tlds/fnc.tld" %> <%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %> <c:set var="ctx" value="${pageContext.request.contextPath}${fns:getAdminPath()}"/> <c:set var="ctxStatic" value="${pageContext.request.contextPath}/static"/> |
可见taglib.jsp
主要是为了引入要再JSP中使用的名字前缀,这类名字前缀主要是分两类,一类是标准标签,如c
,form
,fmt
,fn
标签,他们的uri
属性是一个网址,实质上这个网址上指向的是一个标准定义的tld文件,一类是自定义标签,包含第三方库的自定义标签shiro
,自己定义的自定义标签fns
,fnc
,他们的uri
指向的是本地自定义的tld文件。prefix
属性是使用此标签时的标签名。
以<%@ taglib prefix="fns" uri="/WEB-INF/tlds/fns.tld" %>
为例,我们看一下fns.tld文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | fns.tld 代码片段: <?xml version="1.0" encoding="UTF-8" ?> <taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0"> <description>JSTL 1.1 functions library</description> <display-name>JSTL functions sys</display-name> <tlib-version>1.1</tlib-version> <short-name>fns</short-name> <!-- 通用设置 --> <function> <description>获取管理路径</description> <name>getAdminPath</name> <function-class> com.thinkgem.jeesite.common.config.Global </function-class> <function-signature>j java.lang.String getAdminPath() </function-signature> <example>${fns:getAdminPath()}</example> </function> ...//省略代码 |
该文件实际上是一个前后台连接的枢纽,<short-name>
中的标签就是JSP中可以使用的标签前缀。<function>
中定义的是所需要映射到后台实现类的具体方法,这部分下面会详细解释。
回到sysIndex.jsp
看一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | sysIndex.jsp代码片段: ...//省略代码 <div class="nav-collapse"> <ul id="menu" class="nav"> <c:set var="firstMenu" value="true"/> <c:forEach items="${fns:getMenuList()}" var="menu" varStatus="idxStatus"> <c:if test="${menu.parent.id eq '1' && menu.isShow eq '1'}"> <li class="menu ${firstMenu ? ' active' : ''}"><a class="menu" href="${ctx}/sys/menu/tree?parentId=${menu.id}" target="menuFrame" >${menu.name}</a></li> <c:if test="${firstMenu}"> <c:set var="firstMenuId" value="${menu.id}"/> </c:if> <c:set var="firstMenu" value="false"/> </c:if> </c:forEach> <shiro:hasPermission name="cms:site:select"> <li class="dropdown"> <a class="dropdown-toggle" data-toggle="dropdown" href="#">${fnc:getSite(fnc:getCurrentSiteId()).name}<b class="caret"></b></a> <ul class="dropdown-menu"> <c:forEach items="${fnc:getSiteList()}" var="site"><li><a href="${ctx}/cms/site/select?id=${site.id}&flag=1">${site.name}</a></li></c:forEach> </ul> </li> </shiro:hasPermission> </ul> ...//省略代码 </div><!--/.nav-collapse --> |
<c:set var="firstMenu" value="true"/>
此标签使用了jstl,声明了一个变量firstMenu,值为value,其中c
即由taglib.jsp
中<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
中声明。
<c:forEach items="${fns:getMenuList()}" var="menu" varStatus="idxStatus">
此标签定义了循环,用来显示从后台获取的菜单,其中,items
存储了后台读取来的menu list,var
中存储了每次遍历时,遍历到的菜单对象,用于显示在页面上。
其中fns
由taglib.jsp
中<%@ taglib prefix="fns" uri="/WEB-INF/tlds/fns.tld" %>
声明,并在fns.tld中定义,我们来看一下其中关于getMenuList()
中的定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | fns.tld代码片段: ...//省略代码 <function> <description>获取当前用户的菜单对象列表</description> <name>getMenuList</name> <function-class> com.thinkgem.jeesite.modules.sys.utils.UserUtils </function-class> <function-signature> java.util.List getMenuList() </function-signature> <example>${fns:getMenuList()}</example> </function> ...//省略代码 |
<function>
: 对应于一个具体的函数,声明了JSP中可以使用的函数名,以及跟后台具体实现类的映射。具体如下:
<description>
: 可以理解为函数的注释,用来说明函数的用途。<name>
: 前端JSP中可以使用的函数名,${fns:getMenuList()}
中的getMenuList()就是这个名字。<function-class>
: 指定了一个具体的后台实现类,来真正实现该方法。<function-signature>
: 通常一个tld文件对应一个实现类,里面会有很多方法,函数签名唯一的映射到了后台类的具体某一个函数上。<example>
: 说明了JSP中如何使用该函数,给出了一个示范用法。
接下来我们看一下com/thinkgem/jeesite/modules/sys/utils/中的UserUtils.java文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | UserUtils.java代码片段: public class UserUtils extends BaseService { ... //代码省略 private static MenuDao menuDao = SpringContextHolder.getBean(MenuDao.class); ... //代码省略 public static List<Menu> getMenuList(){ @SuppressWarnings("unchecked") List<Menu> menuList = (List<Menu>)getCache(CACHE_MENU_LIST); if (menuList == null){ User user = getUser(); if (user.isAdmin()){ menuList = menuDao.findAllList(); }else{ menuList = menuDao.findByUserId(user.getId()); } putCache(CACHE_MENU_LIST, menuList); } return menuList; } ... //代码省略 } |
可以看到,UserUtils.java
中的 getMenuList()
方法首先会检查是否缓存了该menu list,如果没有,调用了menuDAO来进行后台数据获取,然后存一份到缓存,并返回一个menu list给前台。具体的DAO层不再深入说明。
至此,整个前端取后台数据并展示到前台的流程就到这里了。