EL和JSTL

2017/03/26 JavaEE

EL

EL表达式用于获取数据,在JSP页面中可使用${标识符}的形式,通知JSP引擎调用pageContext.findAttribute()方法,以标识符为关键字从各个域对象中获取对象。如果域对象中不存在标识符所对应的对象,则返回结果为””(注意,不是null)。

获取bean中属性

<% 
	Person person = new Person();
	Address address = new Address();
	person.setAddress(address);
	
	request.setAttribute("person",person);
%>
<!-- 注意:如果访问bean不存在的属性,会抛 Property 'name' not found on type com.xpress.Address -->
${person.address.name}

获取集合数据

<!-- jsp页面中,使用el表达式获取list集合中指定位置的数据 -->
<% 
	Person p1 = new Person();
	p1.setName("name");
	
	Person p2 = new Person();
	p2.setName("name2");
	
	List list = new ArrayList();
	list.add(p1);
	list.add(p2);
	
	request.setAttribute("list",list);
%>

${list[0].name}

<!-- jsp页面中,使用el表达式获取map集合的数据 -->
<% 
	Map map = new HashMap();
	map.put("a","aa");
	map.put("b","bb");
	map.put("c","cc");
	
	map.put("1","11");
	
	request.setAttribute("map",map);
%>

${map.a}
<!-- 使用.符号取不到时候使用[] -->
${map["1"]} 

EL执行运算

EL运算符

EL运算符

  • empty运算符:检查对象是否为null或“空”
<c:if test="${empty(cart.map)}">
	没有商品
</c:if>
  • 二元表达式:${user!=null?user.name : “”}
  • 和 . 号运算符

EL保留关键字

EL保留关键字.png

获得常用对象

EL表达式语言中定义了11个隐含对象,使用这些隐含对象可以很方便地获取web开发中的一些常见对象,并读取这些对象的数据。

隐含对象名称 描述
pageContext 对应于JSP页面中的pageContext对象(注意:取的是pageContext对象。)
pageScope 代表page域中用于保存属性的Map对象
requestScope 代表request域中用于保存属性的Map对象
sessionScope 代表session域中用于保存属性的Map对象
applicationScope 代表application域中用于保存属性的Map对象
param 表示一个保存了所有请求参数的Map对象
paramValues 表示一个保存了所有请求参数的Map对象,它对于某个请求参数,返回的是一个string[]
header 表示一个保存了所有http请求头字段的Map对象
headerValues 同上,返回string[]数组。注意:如果头里面有“-” ,例Accept-Encoding,则要headerValues[“Accept-Encoding”]
cookie 表示一个保存了所有cookie的Map对象 ${cookie.key.name} ${cookie.key.value}
initParam 表示一个保存了所有web应用初始化参数的map对象

EL函数库

<%@taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
${fn:contains(name, "searchString")}
函数 作用 备注
fn:toLowerCase 转换为小写  
fn:toUpperCase 转换为大写  
fn:trim 删除首尾的空格  
fn:length 返回一个集合或数组大小,或返回一个字符串中包含字符的个数 ${fn:length(shoppingCart.products)}</br>参数为null或者是元素个数为0的集合或数组对象,则函数返回0;如果参数是空字符串,则函数返回0
fn:split 使用分隔符分割字符串  
fn:join 使用分隔符拼接数组  
fn:indexOf 返回指定字符串在一个字符串中第一次出现的索引值 如果第一个参数中不包含第二个参数,则fn:indexOf函数返回-1。如果第二个参数为空字符串,则fn:indexOf函数总是返回0。
fn:contains 检测一个字符串中是否包含指定的字符串 fn:containsIgnoreCase </br> boolean contains(java.lang.String, java.lang.String)
fn:replace 将一个字符串中包含的指定子字符串替换为其它的指定字符串  
fn:substring 截取一个字符串的子字符串并返回截取到的子字符串  
fn:substringAfter 截取并返回一个字符串中的指定子字符串第一次出现之后的子字符串 fn:substringBefore </br> fn:substringAfter(“www.xpress.org”, “.”)的返回值为字符串“xpress.org”。

EL Function调用Java方法

  • 在EL表达式中调用的只能是Java类的静态方法。
  • 这个Java类的静态方法需要在tld文件中描述,才可以被EL表达式调用。

编写Java类

package com.xpress.util;
public class Tool {
    public static int add(String num1, String num2) {
        int a = 0;
        int b = 0;
        try {
            a = Integer.parseInt(num1);
            b = Integer.parseInt(num2);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return a+b;
    }
}

WEB-INF的根目录中编写tld文件

tld文件的例子:\webapps\examples\WEB-INF\jsp2\jsp2-example-taglib.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">
    <tlib-version>1.0</tlib-version>
    <short-name>function</short-name>
    <uri>http://www.xpress.cn</uri>
    <function>
        <name>add</name>
        <function-class>com.xpress.util.Tool</function-class>
        <function-signature>
		int add(java.lang.String,java.lang.String)
		</function-signature>
    </function>
</taglib>

JSP中使用

<%@ taglib prefix="xpress" uri="http://www.xpress.cn"%>
${xpress:add(param.num1,param.num2)}

JSTL

JavaBean组件

  • <jsp:useBean>标签:用于在指定的域范围内查找指定名称的JavaBean对象。
    • 如果存在则直接返回该JavaBean对象的引用。
    • 如果不存在则实例化一个新的JavaBean对象并将它以指定的名称存储到指定的域范围中。
  • <jsp:setProperty>标签:用于在JSP页面中设置一个JavaBean组件的属性。
  • <jsp:getProperty>标签:用于在JSP页面中获取一个JavaBean组件的属性。
<% 
	pageContext.setAttribute("person",new Person());
%>

<!-- class属性必须指定bean的完整类名 -->
<!-- scope取值只能是page、request、session和application等四个值中的一个,其默认值是page -->
<!-- 标签体内容只在实例化bean时执行,如果域中有直接使用则不执行 -->
<jsp:useBean id="person" class="cn.xpress.Person" scope="page">
	xxxx
</jsp:useBean>

<!-- jsp:setProperty标签在工作时,它会自动把字符串转成八种基本数据类型 -->
<jsp:setProperty name="person" property="age" value="12"/>
<!-- 但是jsp:setProperty标签对于复杂类型无法自动进行转换,可以只用表达式处理 -->
<jsp:setProperty name="person" property="birthday" value="<%=new Date() %>"/>

<!-- jsp:setProperty标签可以使用请求参数为bean的属性赋值 -->
<jsp:setProperty name="person" property="name" param="name"/>

<!-- jsp:setProperty标签用所有的请求参数为bean的属性赋值 -->
<!-- http://localhost:8080/xpress/2.jsp?name=xpress&password=123&age=14 -->
<jsp:setProperty name="person" property="*"/>

<!-- 输出 -->
<!-- 如果一个JavaBean实例对象的某个属性的值为null,那么,使用<jsp:getProperty>标签输出该属性的结果将是一个内容为“null”的字符串 -->
<jsp:getProperty name="person" property="name"/>
<%=person.getName()%>

JSTL标签库

  • 核心标签库
  • 国际化标签
  • 数据库标签 (deprecated)
  • XML标签(deprecated)
  • JSTL函数(EL函数)

核心标签库

  • <c:out>标签

用于输出一段文本内容到pageContext对象当前保存的“out”对象中。

属性名 是否支持EL 属性类型 属性描述
value TRUE Object 指定要输出的内容
escapeXml TRUE Boolean 指定是否将>、<、&、’、” 等特殊字符进行HTML编码转换后再进行输出。默认值为true
default TRUE Object 指定如果value属性的值为null时所输出的默认值
<c:out value="${name}" escapeXml="true" default="defaultValue"/>
  • <c:set>标签

用于把某一个对象存在指定的域范围内,或者设置Web域中的java.util.Map类型的属性对象或JavaBean类型的属性对象的属性。

属性名 是否支持EL 属性类型 属 性 描 述
value TRUE Object 用于指定属性值
var FALSE String 用于指定要设置的Web域属性的名称
scope FALSE String 用于指定属性所在的Web域
target TRUE Object 用于指定要设置属性的对象,这个对象必须是JavaBean对象或java.util.Map对象
property TRUE string 用于指定当前要为对象设置的属性名称
<c:set var="key" value="${user}" scope="request"/>
<c:set target="${map}" property="key" value="value"/>
<c:set target="${persion}" property="name" value="value"/>
  • <c:remove>标签

用于删除各种Web域中的属性。

<c:remove var="key" scope="request"/>
  • <c:catch>标签

用于捕获嵌套在标签体中的内容抛出的异常
var属性用于标识标签捕获的异常对象,它将保存在page这个Web域中。

<c:catch var="myex“ scope=“page”>
	<%
		10/0;
	%>
</c:catch>
异常:						<c:out value="${myex}" />
异常 myex.getMessage:		<c:out value="${myex.message}" />
异常 myex.getCause:		<c:out value="${myex.cause}" />
异常 myex.getStackTrace:	<c:out value="${myex.stackTrace}" />
  • <c:if>标签

可以构造简单的“if-then”结构的条件表达式

属性名 是否支持EL 属性类型 属性描述
test TRUE boolean 决定是否处理标签体中的内容的条件表达式
var FALSE String 用于指定将test属性的执行结果保存到某个Web域中的某个属性的名称
scope FALSE String 指定将test属性的执行结果保存到哪个Web域中
<c:if var="result" test="${user==null}" scope="session"/>
  • <c:choose>标签

用于指定多个条件选择的组合边界,可以构造类似 “if-else if-else” 的复杂条件判断结构。

<c:choose>
	<c:when test="${count == 0}">
		对不起,没有符合您要求的记录。
	</c:when>
	<c:otherwise>
		符合您要求的记录共有${count}条.
	</c:otherwise>
</c:choose>
  • <c:forEach>标签

用于对一个集合对象中的元素进行循环迭代操作,或者按指定的次数重复迭代执行标签体中的内容

属性名 是否支持EL 属性类型 属性描述
var FALSE String 指定将当前迭代到的元素保存到page这个Web域中的属性名称
items TRUE 任何支持的类型 将要迭代的集合对象
begin TRUE int 如果指定items属性,就从集合中的第begin个元素开始进行迭代,begin的索引值从0开始编号;如果没有指定items属性,就从begin指定的值开始迭代,直到end值时结束迭代
end TRUE int 参看begin属性的描述
step TRUE int 指定迭代的步长,即迭代因子的迭代增量
<c:forEach items="${array}" var="num" begin="2" end="10" step="3" >
    ${num}
</c:forEach>
  • <c:url>标签

用于在JSP页面中构造一个URL地址,其主要目的是实现URL重写。URL重写就是将会话标识sessionid号以参数形式附加在URL地址后面

属性名 是否支持EL 属性类型 属性描述
value TRUE String 指定要构造的URL
var FALSE String 指定将构造出的URL结果保存到Web域中的属性名称
scope FALSE String 指定将构造出的URL结果保存到哪个Web域中
<!-- 如果不写var会将相对路径直接输出到页面,也可以将标签放入href的值中嵌套使用 -->
<c:url var="link" value="/index.html"/>
<!-- 自动进行url重写和contextPath补全 -->
<a href="${link}">click</a> 
  • <c:param>标签

为标签所使用的URL地址附加参数。标签在为一个URL地址附加参数时,将自动对参数值进行URL编码

<c:url var="link" value="/index.html">
    <c:param name="name" value="中国"/>
</c:url>
  • <c:redirect>标签

用于实现请求重定向

属性名 是否支持EL 属性类型 属性描述
url TRUE String 指定要转发或重定向到的目标资源的URL地址
context TRUE String 当要使用相对路径重定向到同一个服务器下的其他WEB应用程序中的资源时,context属性指定其他WEB应用程序的名称
<c:redirect url="/index.html" context="app2"/>

国际化标签

  • <fmt:formatDate/>标签
<fmt:formatDate value="${date}" pattern="yyyyMMdd"/>
  • <fmt:formatDate/>标签
<!-- 自动补0,四舍五入,使用#.##不补0 -->
<fmt:formatNumber value="3.1415926" pattern="0.00"/>

自定义标签库

自定义标签主要用于移除Jsp页面中的java代码。

Tag接口.png

编写标签

  1. 编写一个实现Tag接口的Java类(标签处理器类)。
  2. 编写标签库描述符(tld)文件,在tld文件中对标签处理器类进行描述。
public class ViewIPTag implements Tag {
	private PageContext pageContext;
	
	public int doStartTag() throws JspException {
		
		HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
		JspWriter out = pageContext.getOut();
		
		String ip = request.getRemoteAddr();
    	try {
			out.write(ip);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		
		return 0;
	}
	
	public int doEndTag() throws JspException {
		return 0;
	}
	public Tag getParent() {
		return null;
	}
	public void release() {
	}
	public void setPageContext(PageContext arg0) {
		this.pageContext = arg0;
	}
	public void setParent(Tag arg0) {
	}
}
<?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>A tag library exercising SimpleTag handlers.</description>
    <tlib-version>1.0</tlib-version>
    <short-name>SimpleTagLibrary</short-name>
    <uri>/xpress</uri>
    <tag>
        <name>viewIP</name>  <!-- 为标签处理器类配一个标签名 -->
		<tag-class>cn.xpress.web.tag.ViewIPTag</tag-class>
		<body-content>empty</body-content>
    </tag>
</taglib>
<%@taglib uri="/xpress" prefix="xpress" %>
<xpress:viewIP/>
标签体类型

tld文件中的四种标签体类型

  • EMPTY
  • JSP
  • scriptless 无脚本类型(无Java代码)
  • tagdepentend 标签依赖

传统标签

Tag接口的执行流程
序号 方法 执行时机
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方法。

标签执行流程图.png

注意:

根据开始标签的执行结果来判断是否执行开始标签后会执行标签体部分
根据结束标签的执行结果来判断是否执行剩余的JSP页面内容

标签扩展功能

通过接口实现方法的返回值可以控制页面展示:

  • 控制jsp页面某一部分内容是否执行。
// extends TagSupport
@Override
public int doStartTag() throws JspException {
	return Tag.SKIP_BODY;
}
  • 控制整个jsp页面是否执行。
// extends TagSupport
@Override
public int doEndTag() throws JspException {
	//return Tag.SKIP_PAGE;  //余下jsp不会执行
	return Tag.EVAL_PAGE;
}
  • 控制jsp页面内容重复执行。
// extends TagSupport
int x = 5;

@Override
public int doStartTag() throws JspException {
	return Tag.EVAL_BODY_INCLUDE;
}

@Override
public int doAfterBody() throws JspException {
	x--;
	if(x>0){
		return IterationTag.EVAL_BODY_AGAIN;
	}else{
		return IterationTag.SKIP_BODY;
	}
}
  • 修改jsp页面内容输出。
// extends BodyTagSupport 

//bodycontent
@Override
public int doStartTag() throws JspException {
	return BodyTag.EVAL_BODY_BUFFERED;
}

@Override
public int doEndTag() throws JspException {
	//拿到标签体
	String content = this.getBodyContent().getString();
	String result = content.toUpperCase();
	try {
		this.pageContext.getOut().write(result);
	} catch (IOException e) {
		throw new RuntimeException(e);
	}
	return Tag.EVAL_PAGE;
}

简单标签

由于传统标签使用三个标签接口来完成不同的功能,显得过于繁琐,不利于标签技术的推广, SUN公司为降低标签技术的学习难度,在JSP 2.0中定义了一个更为简单、便于编写和调用的SimpleTag接口来实现标签的功能。实现SimpleTag接口的标签通常称为简单标签。

SimpleTag执行流程
序号 方法 执行时机
1 setJspContext() WEB容器调用标签处理器对象的setJspContext方法,将代表JSP页面的pageContext对象传递给标签处理器对象。
2 setParent() WEB容器调用标签处理器对象的setParent方法,将父标签处理器对象传递给这个标签处理器对象。注意,只有在标签存在父标签的情况下,WEB容器才会调用这个方法。
3 getParent() 如果调用标签时设置了属性,容器将调用每个属性对应的setter方法把属性值传递给标签处理器对象。如果标签的属性值是EL表达式或脚本表达式,则WEB容器首先计算表达式的值,然后把值传递给标签处理器对象。
4 setJspBody() 如果简单标签有标签体,容器将调用setJspBody方法把代表标签体的JspFragment对象传递进来。
5 doTag() 容器调用标签处理器的doTag()方法,开发人员在方法体内通过操作JspFragment对象,就可以实现是否执行、迭代、修改标签体的目的。在doTag方法中可以抛出javax.servlet.jsp.SkipPageException异常,用于通知WEB容器不再执行JSP页面中位于结束标记后面的内容,这等效于在传统标签的doEndTag方法中返回Tag.SKIP_PAGE常量的情况。

简单标签执行流程图.png

标签扩展功能
  • 控制jsp页面某一部分内容是否执行。
// extends SimpleTagSupport
//简单标签使用这个方法完成所有业务逻辑
@Override
public void doTag() throws JspException, IOException {
	//得到代表标签体的JspFragment
	JspFragment jf = this.getJspBody();
	PageContext pageContext = (PageContext) this.getJspContext();
	
	jf.invoke(pageContext.getOut());// 什么都不做则标签体不执行
}
  • 控制整个jsp页面是否执行。
// extends SimpleTagSupport
@Override
public void doTag() throws JspException, IOException {
	throw new SkipPageException();//抛出异常则不执行
}
  • 控制jsp页面内容重复执行。
// 通过属性控制
private int count;  //<xpress:for count="6">

public void setCount(int count) {
	this.count = count;
}

// extends SimpleTagSupport
@Override
public void doTag() throws JspException, IOException {

	for(int i=0;i<count;i++){
		this.getJspBody().invoke(null);
	}
	
}
  • 修改jsp页面内容输出。
// extends SimpleTagSupport
@Override
public void doTag() throws JspException, IOException {
	JspFragment jf = this.getJspBody();
	StringWriter sw = new StringWriter();
	jf.invoke(sw);

	String content = sw.getBuffer().toString();
	content = content.toUpperCase();

	PageContext pageContent = (PageContext) this.getJspContext();
	pageContent.getOut().write(content);
}

标签属性

  • 在标签处理器中编写每个属性对应的setter方法
  • 在TLD文件中描术标签的属性
<tag>
    <name>demo6</name>  <!-- 为标签处理器类配一个标签名 -->
	<tag-class>cn.xpress.web.simpletag.SimpleTagAttribute</tag-class>
	<body-content>scriptless</body-content>
	<attribute>
		<name>count</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>  <!-- 指示属性的值是否可以为一个表达式 -->
		<type>java.util.Date</type>  <!-- 检查类型是否正确 -->
	</attribute>
</tag>
private int count;  //<xpress:demo5 count="6">
public void setCount(int count) {
	this.count = count;
}
@Override
public void doTag() throws JspException, IOException {
	for(int i=0;i<count;i++){
		this.getJspBody().invoke(null);
	}
}
<%@taglib uri="/simplesxpress" prefix="sxpress"%>
<!-- 属性值是8种基本数据类型引擎会自动转换为相应类型 -->
<sxpress:demo5 count="10">
	hello</br>
</sxpress:demo5>
TLD中描述
元素名 必须 描述
description 用于指定属性的描述信息。
name 用于指定属性的名称。属性名称是大小写敏感的,并且不能以jsp、_jsp、java和sun开头。
required 用于指定在JSP页面中调用自定义标签时是否必须设置这个属性。其取值包括true和false,默认值为false,true表示必须设置,否则可以设置也可以不设置该属性。
rtexprvalue rtexprvalue是runtime expression value(运行时表达式)的英文简写,用于指定属性值是一个静态值或动态值。其取值包括true和false,默认值为false,false表示只能为该属性指定静态文本值,例如”123”;true表示可以为该属性指定一个JSP动态元素,动态元素的结果作为属性值,例如JSP表达式<%=value %>。
type 用于指定属性值的Java类型。

EL和JSTL结合使用

遍历集合

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

<!-- 使用jstl+el表达式可以迭代list集合 -->
<% 
	Person p1 = new Person();
	p1.setName("aa");
	
	Person p2 = new Person();
	p2.setName("bb");
	
	List list = new ArrayList();
	list.add(p1);
	list.add(p2);
	
	request.setAttribute("list",list);
%>

<c:forEach var="person" items="${list}">
	${person.name}<br/>
</c:forEach>

<!-- 使用jstl+el表达式可以迭代map集合 -->
<% 
	Map map = new HashMap();
	map.put("a","aa");
	map.put("b","bb");
	map.put("c","cc");
	map.put("d","dd");
	
	request.setAttribute("map",map);
%>

<%-- Set<Map.Entry> set = map.entrySet()--%>
<c:forEach var="entry" items="${map}">  
	${entry.key} = ${entry.value}<br/>
</c:forEach>

判断

<c:if test="${user!=null}">
	欢迎您:${user.uesrname}
</c:if>

以上概念总结于传智播客JavaWeb课程

Search

    Post Directory