Web-第十二天 el&jstl表达式学习
今日内容介绍
今日内容学习目标
在JSP开发中,为了获取Servlet域对象中存储的数据,经常需要书写很多Java代码,这样的做法会使JSP页面混乱,难以维护,为此,在JSP2.0规范中提供了EL表达式。EL是Expression Language的缩写,它是一种简单的数据访问语言。本节将针对EL表达式进行详细的讲解。
EL(Expression Language) 目的:为了使JSP写起来更加简单。表达式语言的灵感来自于 ECMAScript 和 XPath 表达式语言,它提供了在 JSP 中简化表达式的方法,让Jsp的代码更加简化。
由于EL可以简化JSP页面的书写,因此,在JSP的学习中,掌握EL是相当重要的。要使用EL表达式,首先要学习它的语法。EL表达式的语法非常简单,都是以“${”符号开始,以“}”符号结束的,具体格式如下:
${表达式}
分类 | 内置对象名称 | 描述 |
---|---|---|
作用域 | pageScope | page作用域 |
requestScope | request作用域 | |
sessionScope | session作用域 | |
applicationScope | application作用域 | |
请求参数 | param | 获得一个参数 |
paramValues | 获得一组参数 | |
请求头 | header | 获得一个请求头 |
headerValues | 获得一组请求头 | |
JSP上下文对象 | pageContext | |
全局初始化参数 | initParam | |
cookie | cookie |
<%--初始化数据--%>
<%
pageContext.setAttribute("name", "pValue");
request.setAttribute("name", "rValue");
session.setAttribute("name", "sValue");
application.setAttribute("name", "aValue");
%>
<%--使用JSP脚本获得--%>
<%=pageContext.getAttribute("name") %> <!-- 如果没找到 返回null -->
<%=request.getAttribute("name") %>
<%=session.getAttribute("name") %>
<%=application.getAttribute("name") %>
<%--获得指定作用域的数据--%>
${ pageScope.name } <!-- 返回的是"" -->
${ requestScope.name }
${ sessionScope.name }
${ applicationScope.name }
<%--依次获得数据--%>
${ name } <%-- 底层使用 pageContext.findAttribute("name") ,依次从page、request、session、application获得数据,如果都没有返回null --%>
//请求路径:/day18/a_el.jsp?username=jack&hobby=xxx&hobby=yyy
<%--
param.xxx 对应 request.getParameter("xxx");
paramValue.xxx 对应 request.getParameterValues("xxx");
--%>
${param.username} <br/>
${param.hobby}<br/> <%--获得第一个参数--%>
${paramValues.hobby} <br/> <%--获得一组数据,使用数组 --%>
${paramValues.hobby[1]} <br/> <%--如果是数组,可以使用下标获得 --%>
<%--
header.xxx 对应 request.getHeader("xxx");
headerValues.xxx 对应 request.getHeaders("xxx");
--%>
${header.accept} <br/>
\${header.accept-Encoding} <br/> <%--非法的,有异常,“-”被解析成减号。使用"/"进行单个el表达式转义 --%>
${header['accept-Encoding']} <br/>
${headerValues['accept-Encoding'][0]} <br/>
作者:赵玉刚
当当 广告
购买
<%--
pageContext 对应 pageContext对象
--%>
jsp: <%= ((HttpServletRequest)pageContext.getRequest()).getContextPath() %> <br/>
el : ${pageContext.request.contextPath} <br/>
<%--
web.xml配置
<context-param>
<param-name>person</param-name>
<param-value>白跃</param-value>
</context-param>
initParam 对应 servletContext.getInitParameter("person");
--%>
${initParam.person}
<%--
cookie 没有对应api。底层使用request.getCookies()获得所有cookie,然后遍历并存放到Map中(Map<name,obj>)
--%>
${cookie} <br/> <%--使用Map存所有cookie , Map<名称,对象> --%>
${cookie.company} <%--map.key 获得对应value --%>
${cookie.company.name} <%--通过javabean属性获得属性,获得cookie的名称,对应方法getName()--%>
${cookie.company.value} <%--获得cookie的值值,对应方法getValue() --%>
1)[]用于有下标的数据(数组,list集合) .用于有属性的数据(map,对象)
2)如果属性名中包含有特殊的字符.必须使用[]
<%
String str = "悟空教程";
%>
${str} <%--无法获得,str不在域中 --%>
<%
String s = "Java帮帮";
//将输出存放到作用域
pageContext.setAttribute("sss", s);
%>
${sss} <br/>
${pageScope.sss} <br/>
<%
String[] arr = {"A","B","C"};
pageContext.setAttribute("arr", arr,PageContext.REQUEST_SCOPE);
%>
${arr} <br/>
${arr[1]} <br/>
<%
//模拟数据
List<String> list = new ArrayList<String>();
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
pageContext.setAttribute("list", list);
%>
${list} <br/> <%-- 输出格式:[ , , ] --%>
${list[2]} <br/>
<%
//模拟数据
Map<String,String> map = new HashMap<String,String>();
map.put("li", "小李");
map.put("guo", "小郭");
map.put("wang", "老王");
pageContext.setAttribute("map", map);
%>
${map} <br/> <%-- 输出结果: { k=v ,...} --%>
${map.li} <br/> <%-- 通过key获得数据--%>
<%
Map<String,User> map2 = new HashMap<String,User>();
map2.put("u1", new User("u001","jack",18));
map2.put("u2", new User("u002","rose",21));
map2.put("3", new User("u003","tom",25));
pageContext.setAttribute("map2", map2);
%>
${map2} <br/>
${map2.u2} <br/> <%--通过key获得数据 --%>
${map2.u2.userName} <%--通过javabean 属性获得数据 --%>
${map2['3'].userName} <%--可以通过字符串'3'获得数据,注意:Map.key类型为Integer,将不能获得数据 --%>
<%
pageContext.setAttribute("n1", "10");
pageContext.setAttribute("n2", "20");
pageContext.setAttribute("n3", "30");
pageContext.setAttribute("n4", "40");
%>
${ n1 + n2 + n3 }
${1+1} <br/>
${"1"+1} <br/> <%--将字符串转换成数字,然后进行计算 --%>
${'1'+1} <br/> <%--el没有字符 --%>
\${'a'+1} <br/> <%-- 将a转换数字,异常 --%>
${a + 1} <br/> <%--a将从作用域获得数据,如果没有 --%>
${ n1 < n2 } - ${ n1 lt n2 } <!-- less than --><br/>
${ n1 > n2 } - ${ n1 gt n2 } <!-- great than --><br/>
${ n1 <= n2 } - ${ n1 le n2 } <!-- less equal --><br/>
${ n1 >= n2 } - ${ n1 ge n2 } <!-- great equal --><br/>
${ n1 == n2 } - ${ n1 eq n2 } <!-- equal --><br/>
${ n1<n2 && n3 < n4 } - ${ n1<n2 and n3 < n4 }<br/>
${ n1<n2 || n3 < n4 } - ${ n1<n2 or n3 < n4 }<br/>
${ !(n1 < n2) } - ${ not(n1<n2) }
${ n1 < n2 ? "正确":"错误" }
<%--
1.对象是否为null
2.字符串是否为""
3.集合是否为0
--%>
${ user == null } - ${ empty user }
${ user != null } - ${ not empty user }
从JSP1.1规范开始,JSP就支持使用自定义标签,使用自定义标签大大降低了JSP页面的复杂度,同时增强了代码的重用性。为此,许多Web应用厂商都定制了自身应用的标签库,然而同一功能的标签由不同的Web应用厂商制定可能是不同的,这就导致市面上出现了很多功能相同的标签,令网页制作者无从选择,为了解决这个问题,Sun公司制定了一套标准标签库(JavaServer Pages Standard Tag Library),简称JSTL。
JSTL虽然被称为标准标签库,而实际上这个标签库是由5个不同功能的标签库共同组成的。在JSTL1.1规范中,为这5个标签库分别指定了不同的URI以及建议使用的前缀,如表1-7所示。
表1-1 JSTL包含的标签库
标签库 | 标签库的URI | 前缀 |
---|---|---|
Core | http://java.sun.com/jsp/jstl/core | c |
I18N | http://java.sun.com/jsp/jstl/fmt | fmt |
SQL | http://java.sun.com/jsp/jstl/sql | sql |
XML | http://java.sun.com/jsp/jstl/xml | x |
Functions | http://java.sun.com/jsp/jstl/functions | fn |
通过7.3.1小节的学习,了解了JSTL的基本知识,要想在JSP页面中使用JSTL,首先需要安装JSTL。接下来,分步骤演示JSTL的安装和测试,具体如下:
1.下载JSTL包
从Apache的网站下载JSTL的JAR包。进入“http://archive.apache.org/dist/jakarta/taglibs/standard/binaries/”网址下载JSTL的安装包jakarta-taglibs-standard-1.1.2.zip,然后将下载好的JSTL安装包进行解压,此时,在lib目录下可以看到两个JAR文件,分别为jstl.jar和standard.jar。其中,jstl.jar文件包含JSTL规范中定义的接口和相关类,standard.jar文件包含用于实现JSTL的.class文件以及JSTL中5个标签库描述符文件(TLD)。
2.安装JSTL
将jstl.jar和standard.jar这两个文件复制到day18项目的lib目录下,如图1-16所示。
图1-1 导入jstl.jar和standard.jar文件
从图1-8可以看出,jstl.jar和standard.jar这两个文件已经被导入到day18项目的lib文件夹中,这个过程就相当于在day18项目中安装JSTL,安装完JSTL后,就可以在JSP文件中使用JSTL标签库。
3.测试JSTL
JSTL安装完成后,就需要测试JSTL安装是否成功。由于在测试的时候使用的是<c:out>标签,因此,需要使用taglib指令导入Core标签库,具体代码如下:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
在上述代码中,taglib指令的uri属性用于指定引入标签库描述符文件的URI,prefix属性用于指定引入标签库描述符文件的前缀,在JSP文件中使用这个标签库中的某个标签时,都需要使用这个前缀。
接下来编写一个简单的JSP文件test.jsp,使用taglib指令引入Core标签库,在该文件中使用<c:out>标签,如文件1-12所示。
文件1-1 test.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head></head>
<body>
<c:out value="Hello World!"></c:out>
</body>
</html>
启动Tomcat服务器,打开浏览器,在地址栏中输入地址“http://localhost:8080/chapter07/test.jsp”访问test.jsp页面,此时,浏览器窗口中显示的结果如图1-17所示。
图1-2 test.jsp
从图1-17可以看出,使用浏览器访问test.jsp页面时,输出了“Hello World!”,由此可见,JSTL标签库安装成功了。
在程序开发中,经常需要使用if语句进行条件判断,如果要在JSP页面中进行条件判断,就需要使用Core标签库提供的<c:if>标签,该标签专门用于完成JSP页面中的条件判断,它有两种语法格式,具体如下:
语法1:没有标签体的情况,将结果存放到指定的作用域(不常用)
<c:if test="testCondition" var="result"
[scope="{page|request|session|application}"]/>
语法2:有标签体的情况,在标签体中指定要输出的内容
<c:if test="testCondition" >
body content
</c:if>
在上述语法格式中,可以看到<c:if>标签有三个属性,接下来将针对这三个属性进行讲解,具体如下:
通过前面的讲解,我们对<c:if>标签有了一个简单的认识,接下来通过一个具体的案例来演示如何在JSP页面中使用<c:if>标签。
在WebContent目录下创建一个名为c_if.jsp的文件,代码如文件1-15所示。
文件1-2 c_if.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8" import="java.util.*"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head></head>
<body>
<c:set value="1" var="visitCount" property="visitCount" />
<c:if test="${visitCount==1 }">
This is you first visit. Welcome to the site!
</c:if>
</body>
</html>
启动Tomcat服务器,在浏览器地址栏中输入地址“http://localhost:8080/chapter07/c_if.jsp”访问c_if.jsp页面,此时,浏览器窗口中显示的结果如图1-18所示。
图1-3 c_if.jsp
从图1-18可以看出,浏览器窗口中显示了<c:if>标签体中的内容。这是因为在文件1-15中使用了<c:if>标签,当执行到<c:if>标签时会通过test属性来判断表达式${visitCount==1}是否为true,如果为true就输出标签体中的内容,否则输出空字符串。由于使用了<c:set>标签将visitCount的值设置为1,因此,表达式${visitCount==1}的结果为true,便会输出<c:if>标签体中的内容。
在JSP页面中,经常需要对集合对象进行循环迭代操作,为此,Core标签库提供了一个<c:forEach>标签,该标签专门用于迭代集合对象中的元素,如Set、List、Map、数组等,并且能重复执行标签体中的内容,它有两种语法格式,具体如下:
语法1:迭代包含多个对象的集合
<c:forEach [var="varName"] items="collection" [varStatus="varStatusName"]
[begin="begin"] [end="end"] [step="step"]>
body content
</c:forEach>
语法2:迭代指定范围内的集合
<c:forEach [var="varName"] [varStatus="varStatusName"] begin="begin"
end="end" [step="step"]>
body content
</c:forEach>
在上述语法格式中,可以看到<c:forEach>标签有多个属性。接下来针对这些属性进行讲解,具体如下:
<c:forEach>标签在程序开发中经常会被用到,因此熟练掌握<c:forEach>标签是很有必要的,接下来,通过几个具体的案例来学习<c:forEach>标签的使用。
分别使用<c:foreach>标签迭代数组和Map集合,首先需要在数组和Map集合中添加几个元素,然后将数组赋值给<c:forEach>标签的items属性,而Map集合对象同样赋值给<c:forEach>标签的items属性,之后使用getKey()和getValue()方法就可以获取到Map集合中的键和值,如文件1-17所示。
文件1-3 c_foreach1.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8" import="java.util.*"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head></head>
<body>
<%
String[] fruits = { "apple", "orange", "grape", "banana" };
%>
String数组中的元素:
<br />
<c:forEach var="name" items="<%=fruits%>">
${name}<br />
</c:forEach>
<%
Map userMap = new HashMap();
userMap.put("Tom", "123");
userMap.put("Make", "123");
userMap.put("Lina", "123");
%>
<hr />
HashMap集合中的元素:
<br />
<c:forEach var="entry" items="<%=userMap%>">
${entry.key} ${entry.value}<br />
</c:forEach>
</body>
</html>
启动Tomcat服务器,在浏览器在地址栏中输入地址“http://localhost:8080/chapter07/c_foreach1.jsp”访问c_ foreach1.jsp页面,此时,浏览器窗口中的显示结果如图1-19所示。
图1-4 c_foreach1.jsp
从图1-19可以看出,在String数组中存入的元素apple、orange、grape和banana全部被打印出来了,因此可以说明使用<c:forEach>标签可以迭代数组中的元素。Map集合中存入的用户名和密码全部被打印出来了。在使用<c:forEach>标签时,只需将userMap集合对象赋值给items属性,之后通过entry变量就可以获取到集合中的键和值。
<c:forEach>标签的begin、end和step属性分别用于指定循环的起始索引、结束索引和步长。使用这些属性可以迭代集合对象中某一范围内的元素。
在项目的WebContent目录下,创建一个名为c_foreach2.jsp的文件,该文件中使用了<c:forEach>标签的begin、end和step属性,代码如文件1-14所示。
文件1-4 c_foreach2.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8" import="java.util.*"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head></head>
<body>
colorsList集合(指定迭代范围和步长)<br />
<%
List colorsList=new ArrayList();
colorsList.add("red");
colorsList.add("yellow");
colorsList.add("blue");
colorsList.add("green");
colorsList.add("black");
%>
<c:forEach var="color" items="<%=colorsList%>" begin="1"
end="3" step="2">
${color}
</c:forEach>
</body>
</html>
启动Tomcat服务器,在浏览器地址栏中输入地址“http://localhost:8080/chapter07/c_foreach2.jsp”访问c_ foreach2.jsp页面,此时,浏览器窗口中的显示结果如图1-20所示。
图1-5 c_ foreach2.jsp
从图1-20可以看出,浏览器窗口中显示了colorsList集合中的yellow和green两个元素,只显示这两个元素的原因是,在使用<c:forEach>标签迭代List集合时,指定了迭代的起始索引为1,当迭代集合时首先会输出yellow元素,由于在<c:forEach>标签中指定了步长为2,并且指定了迭代的结束索引为3,因此,还会输出集合中的green元素,其他的元素不会再输出。
<c:forEach>标签的varStatus属性用于设置一个javax.servlet.jsp.jstl.core.LoopTagStatus类型的变量,这个变量包含了从集合中取出元素的状态信息。使用<c:forEach>标签的varStatus属性可以获取以下信息:
通过上面的讲解,读者对<c:forEach>标签的varStatus属性已经有了基本的了解,接下来通过一个具体的案例来演示如何使用<c:forEach>标签的varStatus属性获取集合中元素的状态信息
在项目的WebContent目录下创建一个名为c_foreach3.jsp的文件,代码如文件1-15所示。
文件1-5 c_foreach3.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8" import="java.util.*"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head></head>
<body style="text-align: center;">
<%
List userList = new ArrayList();
userList.add("Tom");
userList.add("Make");
userList.add("Lina");
%>
<table border="1">
<tr>
<td>序号</td>
<td>索引</td>
<td>是否为第一个元素</td>
<td>是否为最后一个元素</td>
<td>元素的值</td>
</tr>
<c:forEach var="name" items="<%=userList%>" varStatus="status">
<tr>
<td>${status.count}</td>
<td>${status.index}</td>
<td>${status.first}</td>
<td>${status.last}</td>
<td>${name}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
启动Tomcat服务器,在浏览器地址栏中输入地址“http://localhost:8080/chapter07/c_foreach3.jsp”访问c_ foreach3.jsp页面,此时,浏览器窗口中的显示结果如图1-21所示。
图1-6 c_ foreach3.jsp
从图1-21可以看出,使用<c:forEach>标签迭代集合中的元素时,可以通过varStatus属性获取集合中元素的序号和索引,而且还可以判断集合中的元素是否为第一个元素以及最后一个元素。因此可以说明使用该属性可以很方便的获取集合中元素的状态信息。
MVC设计模式: Model-View-Controller简写。
MVC是软件工程中的一种软件架构模式,它是一种分离业务逻辑与显示界面的设计方法。它把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。
MVC可对程序的后期维护和扩展提供了方便,并且使程序某些部分的重用提供了方便。而且MVC也使程序简化,更加直观。
注意,MVC不是Java的特有的,几乎现在所有B/S结构的软件都采用了MVC设计模式。
当SUN公司推出JSP后,同时也提供相应的开发模式,JavaWeb经历了JSP Model1 第一代,JSPModel1第二代,JSP Model 2 三个时期。
JSP Model1是JavaWeb早期的模型,它适合小型Web项目,开发成本低!Model1第一代时期,服务器端只有JSP页面,所有的操作都在JSP页面中,连访问数据库的API也在JSP页面中完成。也就是说,所有的东西都耦合在一起,对后期的维护和扩展极为不利。
(高内聚低耦合:)
JSP Model1第二代有所改进,把业务逻辑的内容放到了JavaBean中,而JSP页面负责显示以及请求调度的工作。虽然第二代比第一代好了些,但还让JSP做了过多的工作,JSP中把视图工作和请求调度(控制器)的工作耦合在一起了。
Model2使用到的技术有:Servlet、JSP、JavaBean。Model2 是MVC设计模式在Java语言的具体体现。
JSP模式是理论基础,但实际开发中,我们常将服务器端程序,根据逻辑进行分层。一般比较常见的是分三层,我们称为:经典三层体系架构。三层分别是:表示层、业务逻辑层、数据访问层。
cn.com.javahelp 公司域名倒写
cn.com.javahelp.dao dao层实现
cn.com.javahelp.service service层实现
cn.com.javahelp.web.servlet web层实现
cn.com.javahelp.domain JavaBean
cn.com.javahelp.utils 工具
cn.com.javahelp 公司域名倒写
cn.com.javahelp.xxx 项目名称
cn.com.javahelp.xxx.yyy 子模块
cn.com.javahelp.xxx.yyy.dao 子模块dao层接口
cn.com.javahelp.xxx.yyy.dao.impl 子模块dao层实现类
cn.com.javahelp.xxx.yyy.service 子模块service层接口
cn.com.javahelp.xxx.yyy.service.impl 子模块service层实现类
cn.com.javahelp.xxx.yyy.domain 子模块JavaBean (子模块yyy可省略)
cn.com.javahelp.xxx.yyy.web.servlet 子模块web层,servlet
cn.com.javahelp.xxx.yyy.web.filter 子模块web层,filter
cn.com.javahelp.xxx.utils 工具
cn.com.javahelp.xxx.exception 自定义异常
cn.com.javahelp.xxx.constant 常量
<%--导入核心标签库 --%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%-- 列表 start --%>
<c:forEach items="${requestScope.allProduct}" var="p">
<div>
<a href="product_info.htm">
<img src="${p.pimage}" width="170" height="170" style="display: inline-block;">
</a>
<p><a href="product_info.html" style='color:green'>${p.pname}</a></p>
<p><font color="#FF0000">商城价:¥${p.shop_price}</font></p>
</div>
</c:forEach>
<%-- 列表 end --%>