百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

Java Web轻松学41 - JSTL初步使用

yuyutoo 2024-10-12 01:05 7 浏览 0 评论

本系列文章旨在记录和总结自己在Java Web开发之路上的知识点、经验、问题和思考,希望能帮助更多(Java)码农和想成为(Java)码农的人。

目录

  1. 介绍
  2. JSTL规范下载
  3. JSTL包含哪些库
  4. JSTL如何使用
  5. 租房网应用中使用JSTL
  6. JSTL相关的JAR包
  7. EL表达式访问列表的长度
  8. JSTL的forEach标签
  9. 剩下的页面改造
  10. 总结

介绍

上篇文章我们使用JSP技术对租房网平台进行了改造,也提到下面这样的代码有点奇葩:

<%for (House house : mockHouses) { 
	System.out.println(house); %>
	<li><h2><a href="house-details.jsp?userName=${param.userName}&houseId=<%=house.getId() %>"><%=house.getName() %></a></h2></li>
<%} %>

像这样的代码我们可以使用JSTL技术来解决。当然,JSTL可不仅仅只有这点功能,你还可以定义自己的标签。

这篇文章里,我提到过JSTL是JSP相关的技术,从它的名字全称(JSP Standard Tag Library,即JSP标准标签库)就可以看出来。

在本篇文章里,我们就尝试初步使用JSTL来进一步改造我们的租房网应用。

JSTL规范下载

既然称之为库,那么它包含哪些库呢?

我们可以把JSTL规范下载下来看一下,当然你也可以找本相关书籍,或者直接在网上搜索一下。

JSTL规范的下载类似Servlet规范的下载(可以参考这篇文章),不过我们在JCP官网(https://jcp.org/en/home/index)中搜索的关键字就变成Tag或Tag Library了。

我们在搜索结果中就可以看到:

点击 Download page 链接可以看到:

然后继续点击底部的 Maintenance Review 2 of JSR 52 链接,跳转到:

不过,再次点击DOWNLOAD按钮时,我这边出现无法访问此网站的错误。所以我转而点击底部的 JSR-000052 A Standard Tag Library for JavaServer Pages Detail Page 链接:

从这里我们可以看到JSTL规范的各个阶段,我们选择 Maintenance Release 2 这个阶段,点击它右边的 Download page 链接:

然后再点击红色箭头所指的链接,跳转到真正的下载页面:

后续操作就跟Servlet规范的下载类似了。

JSTL包含哪些库

现在,我们可以打开JSTL规范,可以看到如下描述:

事实上,JSTL应该就只是一个库,但它根据不同功能而划分成了多个库:

  • 核心:变量支持、流控制、URL管理等等,它的命名空间URI是:http://java.sun.com/jsp/jstl/core,标签前缀通常使用:c
  • XML处理:它的命名空间URI是:http://java.sun.com/jsp/jstl/xml,标签前缀通常使用:x
  • 国际化:语言区域、消息格式化、数字和日期格式化等,它的命名空间URI是:http://java.sun.com/jsp/jstl/fmt,标签前缀通常使用:fmt
  • 数据库访问(SQL):它的命名空间URI是:http://java.sun.com/jsp/jstl/sql,标签前缀通常使用:sql
  • 函数:集合长度、字符串操作等,它的命名空间URI是:http://java.sun.com/jsp/jstl/functions,标签前缀通常使用:fn

JSTL如何使用

JSTL的终极目标是简化JSP页面的开发,所以,它应该是在JSP页面中使用。

既然是标签,那它的使用是否跟HTML标签、XML标签类似呢?答案是肯定的。

不过,JSTL标签的使用与XML标签使用时声明命名空间类似,也需要告诉Servlet/JSP容器该JSP页面需要引入某个库(即上述的核心、XML处理、国际化、数据库访问、函数等等,以及以后自定义的标签)。

在JSP页面中是使用一个JSP指令(即taglib指令,之前我们用过page指令)来声明的:

<%@ taglib uri="uri" prefix="prefix" %>

举个例子,假设我们要使用JSTL的核心库,则应该在JSP页面的开头处这样声明:

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

然后,就可以使用核心库的标签,比如out标签:

<c:out value="value" [escapeXml="{true|false}"] [default="defaultValue"]/>
<c:out value="value" [escapeXml="{true|false}"]>
 default value
</c:out>

注意:在标签的语法中,[]表示可选的属性。如果值带下划线,则表示为默认值。

out标签有两种形式,有属性和属性值,也可能有标签内容,跟HTML标签和XML标签类似。

租房网应用中使用JSTL

我们就拿租房网应用中的房源列表页面houses.jsp来使用JSTL改造,因为这里涉及列表数据的展示。

列表数据是很常见的,我们经常可以看到包含列表数据的页面,比如订单列表、商品列表等等。

houses.jsp原来的代码是这样的:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="include.jsp"%>
<%
	List<House> mockHouses = (List<House>) request.getAttribute("mockHouses");
	System.out.println(mockHouses);
%>
<h6>共找到你感兴趣的房源 <%=mockHouses.size() %> 条</h6>
<ul>
<%for (House house : mockHouses) { 
	System.out.println(house); %>
	<li><h2><a href="house-details.jsp?userName=${param.userName}&houseId=<%=house.getId() %>"><%=house.getName() %></a></h2></li>
<%} %>
</ul>
</body>
</html>

首先要引入JSTL中的核心库(因为我们后面要用到的forEach标签是属于核心库的):

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="include.jsp"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

遗憾的是,我们添加这句声明之后,Eclipse就报错了:

提示是说找不到这个标签库的描述符。那就根据这个提示在网上搜索答案呗。

答案就是原来我们还需要在我们的工程结构里配置JSTL相关的JAR包,而Tomcat这个Servlet/JSP容器本身不提供这些JSTL相关的JAR包,我们需要单独下载。

JSTL相关的JAR包

那么在哪里下载呢?既然我们是使用Tomcat这个Servlet/JSP容器,那么我们就可以到它的官网(http://tomcat.apache.org/)上看看:

我们可以看到左侧导航栏中有个Taglibs链接,我们点进去看看:

还真就是JSTL相关JAR包的下载页面,点击Download链接进去,可以找到真正的下载链接:

我们可以看下Binary README文件,里面有该JAR包版本支持的Tomcat和JSP等版本信息,如果我们使用的Tomcat是最新版本(9.0.x),那直接下载下面四个JAR包即可,否则需要点进Archives页面下载历史版本。

好,我们把四个JAR包下载下来之后,就可以添加到我们的租房网应用的工程里面了,可以参考这篇文章

实际上,直接把这四个JAR包拷贝到WebContent/WEB-INF/lib节点下是最快的。

现在,我们可以看到上述的Eclipse报错提示就消失了。

EL表达式访问列表的长度

首先,我们可以使用EL表达式来访问列表的长度:

<h6>共找到你感兴趣的房源 ${mockHouses.size()} 条</h6>

据说低版本的JSP容器不可以这样直接用EL表达式来访问列表的长度,而应该使用JSTL的函数库中的length方法:

${fn:length(list) }

当然,首先需要引入JSTL的函数库。读者朋友可以自行尝试一下。

JSTL的forEach标签

我们可以通过JSTL规范查看一下这个forEach标签的用法:

当然,可能只看这个语法格式还是不太明白如何使用,那么可以继续看规范中的描述,或者直接网上搜索即可。

我们需要改造的代码是这一部分:

<%for (House house : mockHouses) { 
	System.out.println(house); %>
	<li><h2><a href="house-details.jsp?userName=${param.userName}&houseId=<%=house.getId() %>"><%=house.getName() %></a></h2></li>
<%} %>

我们可以先把它注释掉(在Eclipse中可以选中这一段,然后键入Ctrl + Shift + /),然后敲入开始标签的左尖括号 < ,于是Eclipse会出现智能提示:

嗯,这个功能还是挺好用的,提高开发效率。

闲话不多说了,直接上代码:

<c:forEach var="house" items="${mockHouses}">
	<li><h2><a href="house-details.jsp?userName=${param.userName}&houseId=${house.id}">${house.name}</a></h2></li>
</c:forEach>

看似跟之前变化不大,但至少没那么奇葩了,风格也与HTML很一致。

forEach标签遍历列表数据的基本属性是:

  • var:相当于定义一个变量来表示指向列表中的某一项;
  • items:指定需要遍历哪个列表,需要注意的是其值又是使用EL表达式来访问页面/请求/会话/应用中的某个属性数据(即使用setAttribute()添加的对象)

forEach标签的内容就可以是普通的HTML标签了,然后HTML标签里我们就可以使用EL表达式来访问列表中每一项数据。

实际上,EL表达式直接访问对象的属性,而非调用对象的方法,比如:

${house.id}

注意,param是EL的隐式对象,它是由Servlet/JSP容器创建并传进来的,它可以直接访问请求所携带的参数。

所以,我们实际上可以把原来的这一部分:

<%
	List<House> mockHouses = (List<House>) request.getAttribute("mockHouses");
	System.out.println(mockHouses);
%>

删除掉。

现在houses.jsp的代码就变成这样了:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="include.jsp"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<h6>共找到你感兴趣的房源 ${mockHouses.size()} 条</h6>
<ul>
<c:forEach var="house" items="${mockHouses}">
	<li><h2><a href="house-details.jsp?userName=${param.userName}&houseId=${house.id}">${house.name}</a></h2></li>
</c:forEach>
</ul>
</body>
</html>

是不是清晰明朗了许多?

当然,JSP页面的开发者必须知道传进这个页面的到底有哪些数据对象!

没错,这就相当于把数据的展示(视图层)给分离开来,你需要与后端(控制器层和模型层)约定/设计好每一个JSP页面都有哪些数据对象。

然后,JSP页面的开发者和后端(控制器层和模型层)的开发者就可以各自独立去开发了。

剩下的页面改造

剩下的house-details.jsp和house-form.jsp该如何改造呢?大家可以先思考一下。

提示:JSP页面应该只关心取数据展示,而不应该关心如何查找到某个数据这种逻辑,应该把这种逻辑放到后端(控制器层和模型层)。

我的改造是这样的,把原来这两个页面的如何查找到某个数据这种逻辑放到Filter中,前后端约定好这两个页面中存在target这个House对象,于是doFilter()方法中在将请求交给下个节点之前应该挂载上target这个House对象:

		if (userName == null || userName.isEmpty()) {
			System.out.println("invalid user!");
			httpServletResponse.sendRedirect("login.html");
		} else {
			String houseId = httpServletRequest.getParameter("houseId");
			if (houseId != null && !houseId.trim().isEmpty()) {
				House target = findHouseById(houseId);//找不到怎么办?
				httpServletRequest.setAttribute("target", target);
			}
			chain.doFilter(request, response);
		}

另外,应该把如何查找某个房源的逻辑封装起来:

	private House findHouseById(String houseId) {
		for (House house : mockHouses) {
			if (houseId.equals(house.getId())) {
				return house;
			}
		}
		return null;
	}

然后,这两个页面就极其简单了,house-details.jsp是这样的:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="include.jsp"%>
<h2>${target.name}<a href="house-form.jsp?userName=${param.userName}&houseId=${target.id}">编辑</a></h2>
<h3>${target.detail}</h3>
<h4><a href="houses.jsp?userName=${param.userName}">回到列表</a></h4>
</body>
</html>

house-form.jsp是这样的:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="include.jsp"%>
<form action="house-form.servlet" method="post">
<input type="hidden" name="userName" value="${param.userName}"/>
<input type="hidden" name="houseId" value="${target.id}"/>
<label for="house_name">房源名字:</label><input type="text" id="house_name" name="houseName" value="${target.name}" />
<label for="house_detail">房源详细信息:</label><input type="text" id="house_detail" name="houseDetail" value="${target.detail}" />
<input type="submit" value="提交" />
</form>
</body>
</html>

可以看到,这两个页面只是取数据(target这个House对象)展示而已。

总结

  • JSTL的终极目标是简化JSP开发;
  • JSTL的使用需要先声明某个库;
  • JSTL的标签使用类似HTML标签和XML标签,语法规则可以查看JSTL规范;
  • JSP页面使用JSTL和EL表达式基本可以实现大部分功能;
  • EL表达式能够直接访问页面/请求/会话/应用这几个对象中挂载(即setAttribute()方法)的数据对象;
  • EL表达式使用 ${ }
  • EL中存在隐式对象,以后再介绍;
  • 列表数据很常见很重要;
  • 列表数据采用JSTL的forEach标签来遍历(实际上也可以采用EL表达式,比如${mockHouses[i].id});
  • 前后端开发的分离:前端只关心取数据如何展示;后端关心如何取数据并挂载到页面/请求/会话/应用这几个对象中;
  • 前后端需约定/设计好数据;

相关推荐

Mysql和Oracle实现序列自增(oracle创建序列的sql)

Mysql和Oracle实现序列自增/*ORACLE设置自增序列oracle本身不支持如mysql的AUTO_INCREMENT自增方式,我们可以用序列加触发器的形式实现,假如有一个表T_WORKM...

关于Oracle数据库12c 新特性总结(oracle数据库19c与12c)

概述今天主要简单介绍一下Oracle12c的一些新特性,仅供参考。参考:http://docs.oracle.com/database/121/NEWFT/chapter12102.htm#NEWFT...

MySQL CREATE TABLE 简单设计模板交流

推荐用MySQL8.0(2018/4/19发布,开发者说同比5.7快2倍)或同类型以上版本....

mysql学习9:创建数据库(mysql5.5创建数据库)

前言:我也是在学习过程中,不对的地方请谅解showdatabases;#查看数据库表createdatabasename...

MySQL面试题-CREATE TABLE AS 与CREATE TABLE LIKE的区别

执行"CREATETABLE新表ASSELECT*FROM原表;"后,新表与原表的字段一致,但主键、索引不会复制到新表,会把原表的表记录复制到新表。...

Nike Dunk High Volt 和 Bright Spruce 预计将于 12 月推出

在街上看到的PandaDunk的超载可能让一些球鞋迷们望而却步,但Dunk的浪潮仍然强劲,看不到尽头。我们看到的很多版本都是为女性和儿童制作的,这种新配色为后者引入了一种令人耳目一新的新选择,而...

美国多功能舰载雷达及美国海军舰载多功能雷达系统技术介绍

多功能雷达AN/SPY-1的特性和技术能力,该雷达已经在美国海军服役了30多年,其修改-AN/SPY-1A、AN/SPY-1B(V)、AN/SPY-1D、AN/SPY-1D(V),以及雷神...

汽车音响怎么玩,安装技术知识(汽车音响怎么玩,安装技术知识视频)

全面分析汽车音响使用或安装技术常识一:主机是大多数人最熟习的音响器材,有关主机的各种性能及规格,也是耳熟能详的事,以下是一些在使用或安装时,比较需要注意的事项:LOUDNESS:几年前的主机,此按...

【推荐】ProAc Response系列扬声器逐个看

有考牌(公认好声音)扬声器之称ProAcTablette小音箱,相信不少音响发烧友都曾经,或者现在依然持有,正当大家逐渐掌握Tablette的摆位设定与器材配搭之后,下一步就会考虑升级至表现更全...

#本站首晒# 漂洋过海来看你 — BLACK&amp;DECKER 百得 BDH2000L无绳吸尘器 开箱

作者:初吻给了烟sco混迹张大妈时日不短了,手没少剁。家里有了汪星人,吸尘器使用频率相当高,偶尔零星打扫用卧式的实在麻烦(汪星人:你这分明是找借口,我掉毛是满屋子都有,铲屎君都是用卧式满屋子吸的,你...

专题|一个品牌一件产品(英国篇)之Quested(罗杰之声)

Quested(罗杰之声)代表产品:Q212FS品牌介绍Quested(罗杰之声)是录音监听领域的传奇品牌,由英国录音师RogerQuested于1985年创立。在成立Quested之前,Roger...

常用半导体中英对照表(建议收藏)(半导体英文术语)

作为一个源自国外的技术,半导体产业涉及许多英文术语。加之从业者很多都有海外经历或习惯于用英文表达相关技术和工艺节点,这就导致许多英文术语翻译成中文后,仍有不少人照应不上或不知如何翻译。为此,我们整理了...

Fyne Audio F502SP 2.5音路低音反射式落地音箱评测

FyneAudio的F500系列,有新成员了!不过,新成员不是新的款式,却是根据原有款式提出特别版。特别版产品在原有型号后标注了SP字样,意思是SpecialProduction。Fyne一共推出...

有哪些免费的内存数据库(In-Memory Database)

以下是一些常见的免费的内存数据库:1.Redis:Redis是一个开源的内存数据库,它支持多种数据结构,如字符串、哈希表、列表、集合和有序集合。Redis提供了快速的读写操作,并且支持持久化数据到磁...

RazorSQL Mac版(SQL数据库查询工具)

RazorSQLMac特别版是一款看似简单实则功能非常出色的SQL数据库查询、编辑、浏览和管理工具。RazorSQLformac特别版可以帮你管理多个数据库,支持主流的30多种数据库,包括Ca...

取消回复欢迎 发表评论: