JSTL表达式

来源:互联网 发布:网络分销协议 编辑:程序博客网 时间:2024/05/19 20:19

自定义标签

<?xml version="1.0" encoding="UTF-8" ?>


<taglib xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
    version="2.1">
    <tlib-version>1.0</tlib-version>
    <short-name>helloWorldTag</short-name>
    
  
</taglib>


<?xml version="1.0" encoding="UTF-8" ?>


<taglib xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
    version="2.1">
    <tlib-version>1.0</tlib-version>
    <short-name>java1234Tag</short-name>
    
    <tag>
    <name>helloWorld</name>
    <tag-class>
    com.java1234.tag.HelloWorldTag
    </tag-class>
    <body-content>empty</body-content>
    </tag>
    
    <tag>
    <name>helloWorld2</name>
    <tag-class>
    com.java1234.tag.HelloWorldTag2
    </tag-class>
    <body-content>empty</body-content>
    <attribute>
    <name>name</name>
    <required>true</required>
    <rtexprvalue>true</rtexprvalue>//有属性的name 必须要写的的true 是否支持el表达式
    </attribute>
    </tag>
    
    <tag>
    <name>iterate</name>
    <tag-class>
    com.java1234.tag.IterateTag
    </tag-class>
    <body-content>JSP</body-content>//不是empty 有两个值
    <attribute>
    <name>var</name>
    <required>true</required>
    <rtexprvalue>true</rtexprvalue>
    </attribute>
    <attribute>
    <name>items</name>
    <required>true</required>
    <rtexprvalue>true</rtexprvalue>
    </attribute>
    </tag>
    
    <tag>
    <name>iterate2</name>
    <tag-class>
    com.java1234.tag.IterateSimpleTag
    </tag-class>
    <body-content>scriptless</body-content>//简单标签java脚本
    <attribute>
    <name>var</name>
    <required>true</required>
    <rtexprvalue>true</rtexprvalue>
    </attribute>
    <attribute>
    <name>items</name>
    <required>true</required>
    <rtexprvalue>true</rtexprvalue>
    </attribute>
    </tag>
</taglib>




<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.util.*" %>
<%@ taglib prefix="java1234" uri="/WEB-INF/java1234.tld" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<%
List people=new ArrayList();
people.add("王二小");
people.add("丝丝光");
people.add("草泥马");
pageContext.setAttribute("people", people);
%>
</head>
<body>
<java1234:iterate items="people" var="p">
<h2>${p }</h2>
</java1234:iterate>
</body>
</html>


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.util.*" %>
<%@ taglib prefix="java1234" uri="/WEB-INF/java1234.tld" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<%
List people=new ArrayList();
people.add("王二小2");
people.add("丝丝光2");
people.add("草泥马2");
pageContext.setAttribute("people", people);//把people塞入pageContext中
%>
</head>
<body>
<java1234:iterate2 items="people" var="p">//塞的是“people”
<h2>${p }</h2>//取p
</java1234:iterate2>
</body>
</html>


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
11
</body>
</html>


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="java1234" uri="/WEB-INF/java1234.tld" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<java1234:helloWorld2 name="JspServlet屌炸天"/>
</body>
</html>


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="java1234" uri="/WEB-INF/java1234.tld" %>//引入自定义标签
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<java1234:helloWorld/>//通过tldname找到处理类执行到开始想页面输出 
</body>
</html>
//自定义标签可重用不用再页面写很多java代码
package com.java1234.tag;


import java.io.IOException;


import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;


public class HelloWorldTag extends TagSupport{


/**

*/
private static final long serialVersionUID = 1L;


@Override
public int doStartTag() throws JspException {//标签开始的时候执行后台代码
JspWriter out=this.pageContext.getOut();
try {
out.println("自定义标签大爷你好!");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return TagSupport.SKIP_BODY; // 直接结束标签
}




}


package com.java1234.tag;


import java.io.IOException;


import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;


public class HelloWorldTag2 extends TagSupport{


/**

*/
private static final long serialVersionUID = 1L;

private String name;//带属性的

public String getName() {
return name;
}


public void setName(String name) {
this.name = name;
}


@Override
public int doStartTag() throws JspException {
JspWriter out=this.pageContext.getOut();
try {
out.println(name+"自定义标签大爷你好!");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return TagSupport.SKIP_BODY; // 直接结束标签
}




}


package com.java1234.tag;


import java.io.IOException;
import java.util.Iterator;
import java.util.List;


import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
import javax.servlet.jsp.tagext.TagSupport;


public class IterateSimpleTag extends SimpleTagSupport{


/**

*/
private static final long serialVersionUID = 1L;

private String var;//var把集合每次取出一个对象 
private String items;//items 集合名字



public String getVar() {
return var;
}


public void setVar(String var) {
this.var = var;
}


public String getItems() {
return items;
}


public void setItems(String items) {
this.items = items;
}




@Override
public void doTag() throws JspException, IOException {
Object value=this.getJspContext().getAttribute(items);//简单标签 pageContext做不到获取pageContext
if(value!=null && value instanceof List){
Iterator iter=((List)value).iterator();
while(iter.hasNext()){
this.getJspContext().setAttribute(var, iter.next());直接调用页面每次都执行上面代码循环不停调入页面
this.getJspBody().invoke(null); // 响应页面
}
}
}



}


package com.java1234.tag;


import java.util.Iterator;
import java.util.List;


import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;


public class IterateTag extends TagSupport{


/**

*/
private static final long serialVersionUID = 1L;

private String var;
private String items;
private Iterator iter;

public String getVar() {
return var;
}


public void setVar(String var) {
this.var = var;
}


public String getItems() {
return items;
}


public void setItems(String items) {
this.items = items;
}


public Iterator getIter() {
return iter;
}


public void setIter(Iterator iter) {
this.iter = iter;
}


@Override
public int doStartTag() throws JspException {
Object value=this.pageContext.getAttribute(items);
if(value!=null && value instanceof List){//取值 塞一个集合
this.iter=((List)value).iterator();
if(iter.hasNext()){
this.pageContext.setAttribute(var, iter.next());//把值塞给var
return TagSupport.EVAL_BODY_INCLUDE; // 执行标签体
}else{
return TagSupport.SKIP_BODY; // 退出标签执行
}
}else{
return TagSupport.SKIP_BODY; // 退出标签执行
}
}


@Override
public int doAfterBody() throws JspException {//标签体执行完毕之后
if(iter.hasNext()){
this.pageContext.setAttribute(var, iter.next());
return TagSupport.EVAL_BODY_AGAIN; // 再执行一次标签体
}else{
return TagSupport.SKIP_BODY; // 退出标签执行
}
}




}




自定义JSP标签
自定义标签技术是在JSP1.1版本中才出现的,它允许开发人员创建客户化的标签,并且在JSP文件中使用这些标签,这样可以使JSP代码更加简洁。这些可重用的标签能处理复杂的逻辑运算和事务,或者能定义JSP网页的输出内容和格式。
本次课将结合具体的范例,详细介绍自定义标签的创建过程,以及它在JSP文件中的使用方法。
1自定义JSP标签简介
JSP标签包括以下几种形式。
(1)主体内容和属性都为空的标签,例如:
<mm:hello/>  <mm:hello></mm:hello>
(2)包含属性的标签,例如:
<mm:message key=”hello.hi”/>
(3)包含主体内容的标签,例如:
<mm:greeting>How are you.</mm:greeting>
以上<mm:greeting>称为标签的起始标志,</mm:greeting>称为标签的结束标志,两个标签之间的内容“How are you.”称为标签主体。
(4)包含属性和主体内容的标签,例如:
<mm:greeting username=”Tom”> How are you.</mm:greeting>
(5)嵌套的标签,例如:
<mm:greeting>   <c:choose><c:when></c:when></c:choose>
<mm:user name=”Tom” age=”18”/>
</mm:greeting>
以上外层标签<mm:greeting>称为父标签,内层标签<mm:user>称为子标签。
为了便于组织和管理标签,可以把一组功能相关的标签放在同一个标签库中。开发包含自定义标签的标签库包括以下步骤: 
(1)创建自定义标签的处理类(Tag Handler Class)。
(2)创建TLD标签库描述文件(Tag Library Descriptor)。
假定甲方开发了重用性比较高的标签库,那么除了甲方本身的Web应用可以使用它,其他方(如乙方)也可以使用它。JSTL Core标签库的使用介绍了如何在Web应用中使用由第三方提供的JSP标准标签库(JSTL)。
本次课将按照如下步骤在Web应用中使用标签库:
(1)把标签处理类及相关类的class文件存放在WEB-INF/classes目录下。
(2)把TLD标签库描述文件存放在WEB-INF目录或者其自定义的子目录下。
(3)在web.xml文件中声明所引用的标签库。
(4)在JSP文件中使用标签库中的标签。
2JSP Tag API
Servlet容器在运行JSP文件时,如果遇到自定义标签,就会调用这个标签的处理类(Tag Handler Class)的相关方法。标签处理类可以继承JSP Tag API中的TagSupport类或者BodyTagSupport类。
JSP Tag API位于javax.servlet.jsp.tagext包中,图13-1是其中的主要接口和类的类框图。
2.1JspTag接口
所有的标签处理类都要实现JspTag接口。这个接口只是一个标识接口,没有任何方法,主要是作为Tag和SimpleTag接口的共同接口。在JSP2.0以前,所有的标签处理类都要实现Tag接口,实现该接口的标签称为传统标签(Classic Tag)。JSP2.0提供了SimpleTag接口,实现该接口的标签称为简单标签(Simple Tag)。本章将介绍传统标签的用法。
2.2Tag接口
Tag接口定义了所有传统标签处理类都要实现的基本方法,包括以下几种。
setPageContext(PageContext pc):由Servlet容器调用该方法,向当前标签处理对象(即Tag对象)传递当前的PageContext对象。
setParent(Tag t):由Servlet容器调用该方法,向当前Tag对象传递父标签的Tag对象。
getParent():返回Tag类型的父标签的Tag对象。
release():当Servlet容器需要释放Tag对象占用的资源时,会调用此方法。
doStartTag():当Servlet容器遇到标签的起始标志时,会调用此方法。doStartTag()方法返回一个整数值,用来决定程序的后续流程。它有两个可选值,即Tag.SKIP_BODY和Tag.EVAL_BODY_INCLUDE。Tag.SKIP_BODY表示标签之间的主体内容被忽略,Tag.EVAL_BODY_INCLUDE表示标签之间的主体内容被正常执行。例如对于以下代码:
<prefix:mytag>
Hello World
……
</prefix:mytag>
假若<mytag>标签的处理对象的doStartTag()方法返回Tag.SKIP_BODY,那么“Hello World”字符串不会显示在网页上;若返回Tag.EVAL_BODY_INCLUDE,那么“Hello World”字符串将显示在网页上。
doEndTag():当Servlet容器遇到标签的结束标志时,就会调用doEndTag()方法。doEndTag()方法也返回一个整数值,用来决定程序后续流程。它有两个可选值,即Tag.SKIP_PAGE和Tag.EVAL_PAGE。Tag.SKIP_PAGE表示立刻停止执行标签后面的JSP代码,网页上未处理的静态内容和Java程序片段均被忽略,任何已有的输出内容立刻返回到客户的浏览器上。Tag.EVAL_PAGE表示按正常的流程继续执行JSP文件按。
以上提到的Tag.SKIP_BODY、Tag.EVAL_BODY_INCLUDE、Tag.SKIP_PAGE和Tag.EVAL_PAGE是在Tag接口中定义的4个int类型的静态常量,用于指示标签处理流程。
标签处理类的对象(Tag对象)由Servlet容器负责创建。Servlet容器在执行JSP文件时,如果遇到JSP文件中的自定义标签,就会寻找缓存中的相关的Tag对象,如果还不存在,就创建一个Tag对象,把它放在缓存中,以便下次处理自定义标签时重复使用。当Servlet容器得到了Tag对象后,会按照如图13-2所示的流程调用Tag对象的相关方法:
(1)Servlet容器调用Tag对象的setPageContext()和setParent()方法,把当前JSP页面的PageContext对象及父标签处理对象传给当前Tag对象。如果不存在父标签,则把父标签处理对象设为null。
(2)Servlet容器调用Tag对象的一系列set方法,设置Tag对象的属性。如果标签没有属性,则无需这个步骤。
(3)Servlet容器调用Tag对象的doStartTag()方法。
(4)如果doStartTag()方法返回Tag.SKIP_BODY,就不执行标签主体的内容;如果doStartTag()方法返回Tag.EVAL_BODY_INCLUDE,就执行标签主体的内容。
(5)Servlet容器调用Tag对象的doEndTag()方法。
(6)如果doEndTag()方法返回Tag.SKIP_PAGE,就不执行标签后续的JSP代码;如果doEndTag()方法返回Tag.EVAL_PAGE,就执行标签后续的JSP代码。
注:
一个Tag对象在被创建后,就会一直存在,可以被Servlet容器重复调用。当Web应用终止时,Serlvet容器会先调用该Web应用中的所有Tag对象的release()方法,然后销毁这些Tag对象。
2.3IterationTag接口
IterationTag接口继承自Tag接口,IterationTag接口增加了重复执行标签主体内容的功能。
IterationTag接口定义了一个doAfterBody()方法,Servlet容器在执行完标签主体内容后,会调用此方法。如果Serlvet容器未执行标签主体内容,那么就不会调用此方法。doAfterBody()方法也返回一个整数值,用来决定程序后续流程,它有两个可选值:Tag.SKIP_BODY和IterationTag.EVAL_BODY_AGAIN。Tag.SKIP_BODY表示不再执行标签主体内容;IterationTag.EVAL_BODY_AGAIN表示重复执行标签主体内容。
IterationTag接口还定义了一个可作为doAfterBody()方法的返回值得int类型的静态常量:IterationTag.EVAL_BODY_AGAIN,用于指示Servlet容器重复执行标签主体内容。
Servlet容器在处理JSP文件中的这种标签时,会寻找缓存中的相关的IterationTag对象,如果还不存在,就创建一个IterationTag对象,把它放在缓存中,以便下次处理自定义标签时重复使用。Servlet容器在得到了IterationTag对象后,会按照如图13-3所示的流程调用IterationTag对象的相关方法:
(1)Servlet容器调用IterationTag对象的setPageContext()和setParent()方法,把当前JSP页面的PageContext对象及父标签处理对象传给当前IterationTag对象。如果不存在父标签,则把父标签处理对象设为null。
(2)Servlet容器调用IterationTag对象的一系列set方法,设置Tag对象的属性。如果标签没有属性,则无需这个步骤。
(3)Servlet容器调用IterationTag对象的doStartTag()方法。
(4)如果doStartTag()方法返回Tag.SKIP_BODY,就不执行标签主体的内容;如果doStartTag()方法返回Tag.EVAL_BODY_INCLUDE,就执行标签主体的内容。
(5)如果在步骤(4)中Servlet容器执行了标签主体的内容,那么就调用doAfterBody()方法。
(6)如果doAfterBody()方法返回Tag.SKIP_BODY,就不再执行标签主体的内容;如果doAfterBody()方法返回IterationTag.EVAL_BODY_AGAIN,就继续重复执行标签主体的内容。
(7)Servlet容器调用IterationTag对象的doEndTag()方法。
(8)如果doEndTag()方法返回Tag.SKIP_PAGE,就不执行标签后续的JSP代码;如果doEndTag()方法返回Tag.EVAL_PAGE,就执行标签后续的JSP代码。
与Servlet容器调用Tag对象的流程相比,可以看出,以上步骤(5)和步骤(6)是增加的步骤。
2.4BodyTag接口
BodyTag接口继承自IterationTag接口,增加了直接访问和操纵标签主体内容的功能。BodyTag接口定义了两个方法。
setBodyContent(BodyContent bc):Servlet容器通过此方法向BodyTag对象传递一个用于缓存标签主体的执行结果的BodyConent对象。
doInitBody():当Servlet容器调用完setBodyContent()方法之后,在第一次执行标签主体之前,先调用此方法,该方法用于为执行标签主体做初始化工作。
只要符合以下两种条件之一,setBodyContent(BodyContent bc)和doInitBody()就不会被Servlet容器调用:
标签主体为空。
doStartTag()方法的返回值为Tag.SKIP_BODY或者Tag.EVAL_BODY_INCLUDE。
只有同时符合以下两个条件,Servlet容器才会调用setBodyContent(BodyContent bc)和doInitBody()方法:
标签主体不为空。
doStartTag()方法的返回值为BodyTag.EVAL_BODY_BUFFERED。
以上提到的BodyTag.EVAL_BODY_BUFFERED是在BodyTag接口中定义的int类型的静态常量,它可作为doStartTag()方法的返回值,指示Servlet容器调用BodyTag对象的setBodyContent()和doInitBody()方法。
Servlet容器在处理JSP文件中的这种标签时,会寻找缓存中的相关的BodyTag对象,如果还不存在,就创建一个BodyTag对象,把它放在缓存中,以便下次处理自定义标签时重复使用。Servlet容器在得到了BodyTag对象后,会按照如图13-4所示的流程调用BodyTag对象的相关方法:
(1)Servlet容器调用BodyTag对象的setPageContext()和setParent()方法,把当前JSP页面的PageContext对象及父标签处理对象传给当前BodyTag对象。如果不存在父标签,则把父标签处理对象设为null。
(2)Servlet容器调用BodyTag对象的一系列set方法,设置Tag对象的属性。如果标签没有属性,则无需这个步骤。
(3)Servlet容器调用BodyTag对象的doStartTag()方法。
(4)如果doStartTag()方法返回Tag.SKIP_BODY,就不执行标签主体的内容;如果doStartTag()方法返回Tag.EVAL_BODY_INCLUDE,就执行标签主体的内容;如果doStartTag()方法返回BodyTag.EVAL_BODY_BUFFERED,就先调用setBodyContent()和doInitBody()方法,再执行标签主体的内容。
(5)如果在步骤(4)中Servlet容器执行了标签主体的内容,那么就调用doAfterBody()方法。
(6)如果doAfterBody()方法返回Tag.SKIP_BODY,就不再执行标签主体的内容;如果doAfterBody()方法返回IterationTag.EVAL_BODY_AGAIN,就继续重复执行标签主体的内容。
(7)Servlet容器调用BodyTag对象的doEndTag()方法。
(8)如果doEndTag()方法返回Tag.SKIP_PAGE,就不执行标签后续的JSP代码;如果doEndTag()方法返回Tag.EVAL_PAGE,就执行标签后续的JSP代码。
2.5TagSupport类和BodyTagSupport类
TagSupport类和BodyTagSupport类是标签实现类,其中TagSupport类实现了IterationTag接口,而BodyTagSupport类则继承自TagSupport类,并且实现了BodyTag接口。用户自定义的标签处理类可以继承TagSupport类或者BodyTagSupport类。例程13-1是TagSupport类的部分源代码。
import java.io.Serializable;
import java.util.Enumeration;
import java.util.Hashtable;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.IterationTag;
import javax.servlet.jsp.tagext.Tag;


public class TagSupport implements IterationTag, Serializable {
public static final Tag findAncestorWithClass(Tag from,
@SuppressWarnings("unchecked") Class klass) {
boolean isInterface = false;
if (from == null
|| klass == null
|| (!Tag.class.isAssignableFrom(klass) && !(isInterface = klass
.isInterface()))) {
return null;
}
for (;;) {
Tag tag = from.getParent();


if (tag == null) {
return null;
}
if ((isInterface && klass.isInstance(tag))
|| klass.isAssignableFrom(tag.getClass()))
return tag;
else
from = tag;
}
}
public TagSupport() {
}
public int doStartTag() throws JspException {
return SKIP_BODY;
}
public int doEndTag() throws JspException {
return EVAL_PAGE;
}
public int doAfterBody() throws JspException {
return SKIP_BODY;
}
public void release() {
parent = null;
id = null;
if (values != null) {
values.clear();
}
values = null;
}
public void setParent(Tag t) {
parent = t;
}
public Tag getParent() {
return parent;
}
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
public void setPageContext(PageContext pageContext) {
this.pageContext = pageContext;
}
public void setValue(String k, Object o) {
if (values == null) {
values = new Hashtable<String, Object>();
}
values.put(k, o);
}
public Object getValue(String k) {
if (values == null) {
return null;
} else {
return values.get(k);
}
}
public void removeValue(String k) {
if (values != null) {
values.remove(k);
}
}
public Enumeration<String> getValues() {
if (values == null) {
return null;
}
return values.keys();
}
private Tag parent;
private Hashtable<String, Object> values;
protected String id;
protected PageContext pageContext;
}
1、parent和pageContext成员变量
TagSupport类有两个重要的成员变量。
parent:private访问级别的成员变量,代表父标签的处理对象。
pageContext:protected访问级别的成员变量,代表当前JSP页面的PageContext对象。
Servlet容器在调用doStartTag()方法前,会先调用setPageContext()和setParent()方法,设置pageContext和parent成员变量,因此在TagSupport子类的doStartTag()或doEndTag()等方法中可以通过getParent()方法获取父标签的处理对象。在TagSupport类中定义了protected访问级别的pageContext成员变量,因此在TagSupport子类的doStartTag()或doEndTag()等方法中可以直接访问pageContext变量。JSP课程中(PageContext抽象类)已经介绍了PageContext类的作用,它在标签处理类中将大有用武之地。在本章及下一章的标签处理类的例子中,都会用到PageContext类。


注:
在TagSupport的构造方法中不能访问pageContext成员变量,因为此时Servlet容器还没有调用setPageContext()方法对pageContext成员变量进行初始化。
2、处理标签的方法
对于用户自定义的标签处理类,主要重新实现TagSupport类中的以下方法。
doStartTag():提供Servlet容器在遇到标签起始标志时执行的操作。
doEndTag():提供Servlet容器在遇到标签结束标志时执行的操作。
如果希望Servlet容器重复执行标签主体的内容,那么还可以重新实现TagSupport类的doAfterBody()方法。
3、用户自定义的标签属性
如果在标签中包含自定义的属性,例如:
<prefix:mytag username=”Tom”>
……
</prefix:mytag>
那么在标签处理类中应该将这个username属性作为成员变量,并且分别提供设置和读取属性的方法。假定以上username为String类型,可以定义如下方法:
private String username;
public void setUsername(String username){
this.username = username;
}
public String getUsername(){
return username;
}
Servlet容器在调用标签处理对象的doStartTag() 方法之前,会先调用以上setUsername(String username)方法,把标签中的username属性的值“Tom”赋值给标签处理对象的username成员变量。


注:
对于以上<prefix:mytag>标签中的username属性,由于Servlet容器在调用相应标签处理对象的doStartTag()方法之前,会先调用setUsername(String username)方法,因此在标签处理类中必须提供setUsername(String username)方法,而username成员变量和getUsername()方法不是必须的,可以根据实际需要来决定是否定义它们。
如果希望操纵标签主体内容,可以让自定义的标签处理类继承BodyTagSupport类。例程13-2是BodyTagSupport类的部分源代码。
例程13-2 BodyTagSupport.java
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTag;


public class BodyTagSupport extends TagSupport implements BodyTag {
public BodyTagSupport() {
super();
}
public int doStartTag() throws JspException {
return EVAL_BODY_BUFFERED;
}
public int doEndTag() throws JspException {
return super.doEndTag();
}
public void setBodyContent(BodyContent b) {
this.bodyContent = b;
}
public void doInitBody() throws JspException {
}
public int doAfterBody() throws JspException {
return SKIP_BODY;
}
public void release() {
bodyContent = null;
super.release();
}
public BodyContent getBodyContent() {
return bodyContent;
}
public JspWriter getPreviousOut() {
return bodyContent.getEnclosingWriter();
}
protected BodyContent bodyContent;
}
BodyTagSupport类有个重要的bodyContent成员变量,它是protected访问级别的成员变量,为javax.servlet.jsp.tagext.BodyContent类型,用于缓存标签主体的执行结果。
如果标签处理类的doStartTag()方法返回BodyTag.EVAL_BODY_BUFFERED,那么Servlet容器在执行标签主体之前,会先创建一个用来缓存标签主体的执行结果的BodyContent对象,接着调用setBodyContent(BodyContent bc)方法,得到bodyContent成员变量引用BodyContent对象,然后再调用doInitBody()方法。Servlet容器在执行标签主体内容时,会把得到的执行结果缓存到BodyContent对象中。
在标签处理类中可以直接访问bodyContent成员变量,也可以通过getBodyContent()方法得到BodyContent对象。BodyContent类的getString()方法返回字符串形式的标签主体的执行结果。
3创建标签库描述文件
标签库描述文件(Tag Library Descriptor,TLD),采用XML文件格式,对标签库及库中的标签做了描述。TLD文件中的元素可以分为3类:
<taglib>:标签库元素。
<tag>:标签元素。
<attribute>:标签属性元素。
1、标签库元素<taglib>
标签库元素<taglib>用来设定标签库的相关信息,它的子元素说明参见表13-2。
表13-2 <taglib>元素的子元素
2、标签元素<tag>
标签元素<tag>用来定义一个标签,它的子元素说明参见表13-3。
表13-3 <tag>元素的子元素
以上<tag>元素的<body-content>子元素用于设定标签主体的类型,可选值包括:
empty:标签主体为空。
scriptless:标签主体不为空,并且包含JSP的EL表达式和动作元素,但不能包含JSP的脚本元素。所谓动作元素是指<jsp:include>和<jsp:forward>等以“jsp”为前缀的JSP内置标签。所谓脚本元素是指“<%!”和“%>”、“<%”和“%>”和“<%=”和“%>”这3种以“<%”开头的JSP标记。
JSP:标签主体不为空,并且包含JSP代码。在JSP代码中可以包含EL表达式、动作元素和脚本元素。<body-content>子元素的scriptless可选值与jsp可选值的区别在于前者不能包含JSP的脚本元素。
tagdependant:标签主体不为空,并且标签主体内容由标签处理类来解析和处理。标签主体的所有代码都会原封不动的传给标签处理类,而不是把标签主体的执行结果传给标签处理类。假定用户定义了一个<sql:query>标签,它的<body-content>元素的值为tagdependant。以下JSP代码使用了<sql:query>标签:
<sql:query>
select * from MemberDB where ID,10
</sql:query>
这段代码中的标签主体为一个SQL语句,它将由<sql:query>标签的处理类来处理,该类负责执行这个SQL语句。
3、标签属性元素<attribute>
标签属性元素<attribute>用来描述标签的属性,<attribute>元素的子元素说明参见表
在<attribute>元素中包括一个<rtexprvalue>子元素,如果取值为true,表示标签的属性可以为普通的字符串,或者是基于“<%=”和“%>”形式的Java表达式或者EL表达式;如果为false,表示标签的属性只能为普通的字符串。例如对于以下mytag标签,它的num属性就是一个Java表达式,因此当在TLD文件中定义mytag标签的num属性时,应该把<rtexprvalue>子元素设为true:
<%int num=1;%>
<prefix:mytag num=”<%=num%>”/>


注:
“rtexprvalue”是“runtime expression value”的缩写,表示运行时表达式,包括基于“<%=”和“%>”形式的Java表达式或者EL表达式。
下面将创建TLD文件,命名为“mytaglib.tld”。在这个文件中定义了uri为“/mytaglib”的标签库,本章创建的所有标签都位于这个标签库中。例程13-6是mytaglib.tld文件的源代
码,它定义了一个“message”的标签,这个标签有一个名为“key”的属性。本章后文还会介绍向mytaglib.tld文件中加入其他范例标签的定义代码。
<?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.1</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>mm</short-name>
<uri>/mytaglib</uri>


<tag>
<name>message</name>
<tag-class>mypack.MessageTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>key</name>
<required>true</required>
</attribute>
</tag>
</taglib>
由于<message>标签的主体为空,因此以上<body-content>子元素的值为“empty”。当在JSP文件中使用<message>标签时,必须为标签设置key属性,因此<attribute>元素的<required>子元素的值为“true”。例如在以下JSP代码中,<mm: message key=“hello.hi“>是合法的,而<mm: message/>是不合法的。
<mm:message key=“hello.hi“/>:${param.username}
<mm:message/>:${param.username}
在Web应用中使用标签
如果在Web应用中用到了特定标签库中的自定义标签,则应该在web.xml文件中加入<taglib>元素,它用于声明所引用的标签库:
<jsp-config>
<taglib>
<taglib-uri>/mytaglib</taglib-uri>
<taglib-location>/WEB-INF/mytaglib.tld</taglib-location>
</taglib>
</jsp-config>
在JSP文件中需要通过<%@taglib>指令来声明对标签库的引用,例如:
<%@taglib uri=”/mytaglib” prefix=”mm”%>
以上<%@taglib>指令中的uri属性用来指定标签库的标识符,它和web.xml中的<taglib-uri>元素的值保持一致。prefix属性表示在JSP文件中引用这个标签库中的标签的前缀,例如,以下代码表示引用mytaglib标签库中的<message>标签:
<title><mm:message key=”hello.title”/></title>


注:
在Web应用中引入标签库实际上有两种方式,除了按照本章介绍的方式在web.xml文件中声明引入的标签库,还可以直接使用第三方提供的符合特定规范的标签库的JAR打包文件。 (JSTL就是使用第三方提供的标签库)。

JSTL

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<c:catch var="errMsg">//处理程序中的异常
<%
int a=1/0;
%>
</c:catch>
<h2>异常信息:${errMsg }</h2>
</body>
</html>


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<jsp:useBean id="people" class="com.java1234.model.People" scope="page"></jsp:useBean>
<c:set property="id" target="${people }" value="007"></c:set>
<c:set property="name" target="${people }" value="王二小"></c:set>
<c:set property="age" target="${people }" value="19"></c:set>




<c:choose>
<c:when test="${people.age<18 }">
<h2>小于18</h2>
</c:when>
<c:when test="${people.age==18 }">
<h2>等于18</h2>
</c:when>
<c:otherwise>
<h2>大于18</h2>
</c:otherwise>
</c:choose>
</body>
</html>


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="com.java1234.model.*"%>
<%@ page import="java.util.*"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
String dogs[]={"小黑","小黄","小白","小小"};//数组每次遍历都会产生一个对象用var dog接受
    pageContext.setAttribute("dogs",dogs);//把内容放到pageContext中
%>
<c:forEach var="dog" items="${dogs }">
${dog }
</c:forEach>
<hr/>
<c:forEach var="dog" items="${dogs }" step="2">//取2步
${dog }
</c:forEach>
<hr/>
<c:forEach var="dog" items="${dogs }" begin="1" end="2">//1第二个位置索引
${dog }
</c:forEach>
<hr/>
<%
List<People> pList=new ArrayList<People>();
    pList.add(new People(1,"张三",10));
    pList.add(new People(2,"李四",20));
    pList.add(new People(3,"王五",30));
    pageContext.setAttribute("pList",pList);
%>
<table>
<tr>
<th>编号</th>
<th>姓名</th>
<th>年龄</th>
</tr>
<c:forEach var="p" items="${pList }">
<tr>
<td>${p.id }</td>
<td>${p.name }</td>
<td>${p.age }</td>
</tr>
</c:forEach>
</table>
</body>
</html>


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
String str1="www.java1234.com";
String str2="张三,李四,王五";
    pageContext.setAttribute("str1",str1);
    pageContext.setAttribute("str2",str2);
%>
<c:forTokens items="${str1 }" delims="." var="s1">//分隔开每个遍历的数据用s1表示
${s1 }
</c:forTokens>
<hr/>
<c:forTokens items="${str2 }" delims="," var="s2">
${s2 }
</c:forTokens>
</body>
</html>


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<jsp:useBean id="people" class="com.java1234.model.People" scope="page"></jsp:useBean>
<c:set property="id" target="${people }" value="007"></c:set>
<c:set property="name" target="${people }" value="王二小"></c:set>
<c:set property="age" target="${people }" value="16"></c:set>
<c:if test="${people.name=='王二小' }" var="r" scope="page">//var 返回结果底层需要的
<h2>是王二小</h2>
</c:if>
<c:if test="${people.age<18 }">
<h2>是未成年</h2>
</c:if>
</body>
</html>


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<c:import url="c_forEach.jsp"></c:import>
<c:import url="c_if.jsp"></c:import>
</body>
</html>


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
pageContext.setAttribute("people","张三");
%>
<h2><c:out value="${people}"></c:out></h2>
<h2><c:out value="${people2}" default="某人"></c:out></h2>//JSTL特有功能 


</body>
</html>


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<c:redirect url="target.jsp">//重定向
<c:param name="name" value="xiaofeng"></c:param>
<c:param name="age" value="26"></c:param>
</c:redirect>
</body>
</html>


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<c:set var="people" value="张三" scope="request"></c:set>//相当于new了一个string对象
<h2><c:out value="${people}" default="没人啊"></c:out></h2>
<c:remove var="people" scope="request"/>
<h2><c:out value="${people}" default="没人啊"></c:out></h2>
</body>
</html>


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<c:set var="people" value="张三" scope="request"></c:set>
<h2><c:out value="${people}"></c:out></h2>
<jsp:useBean id="people2" class="com.java1234.model.People" scope="page"></jsp:useBean>
<c:set property="id" target="${people2 }" value="007"></c:set>//给id设值给哪个对象 对对象设值
<c:set property="name" target="${people2 }" value="王二小"></c:set>
<c:set property="age" target="${people2 }" value="16"></c:set>
<h2>编号:${people2.id }</h2>
<h2>姓名:${people2.name }</h2>
<h2>年龄:${people2.age }</h2>
</body>
</html>


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<c:url value="http://www.java1234.com" var="url">//value生成地址存到对象url中
<c:param name="name" value="xiaofeng"></c:param>
<c:param name="age" value="26"></c:param>
</c:url>
<a href="${url }">Java知识分享网</a>
</body>
</html>


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<c:out value="jstl大爷你好"></c:out>//页面输出
</body>
</html>


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>姓名:${param.name }</h2>//重定向取值
<h2>年龄:${param.age }</h2>
</body>
</html>


2.JSTL的core标签库
2.1.<c:out>标签
<c:out>标签用于计算一个表达式并将结果输出到当前的JspWriter对象。<c:out>标签的功能类似于JSP的表达式<%=expression%>。
<c:out>标签的语法格式如下:
<c:out value="表达式" escapeXml="是否转义" default="默认值"></c:out>
value属性:指定被计算的表达式。
escapeXml属性:确定在结果字符中的字符“<”、“>”、“’”、“””和“&”是否应该被转换为对应的字符引用或预定义实体引用,默认值为true。
如果值为true,那么字符“<”、“>”、“’”、“””和“&”将按照如下表进行转换。
default属性:如果value为null,那么将使用这个默认值。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title> out.jsp </title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">    
  </head>
  <body>
    <%
    pageContext.setAttribute("name", "longestory");
    %>
    <c:out value="${name}"></c:out><br/>
    <c:out value="<script>alert('hello longestory.');</script>" escapeXml="false"></c:out><br/>
    <c:out value="${helloworld}" default="unknown"></c:out>
  </body>
</html>
2.2.<c:set>标签
<c:set>标签用于设置范围变量的值或者JavaBean对象的属性。
<c:set>标签的语法格式如下:
<c:set var="变量名称" value="表达式" scope="JSP域范围"></c:set>
var属性:将value属性计算表达式得到的结果,保存在该变量名称中。
value属性:指定被计算的表达式。
scope属性:var属性指定的变量所使用的范围(JSP域范围)。
target属性:要设置属性的对象。必须是JavaBean对象(对应的属性有setter方法)或者java.util.Map对象。
property属性:要设置的target对象的属性名称。
下面是<c:set>标签的具体用法:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
<title>set.jsp</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">    
  </head>
  <body>
    <c:set var="name" value="longestory" scope="session"></c:set>
    <c:out value="name"></c:out>
    <br>
    <jsp:useBean id="user" class="app.java.bean.User" scope="session" />
    <c:set target="${user }" property="age" value="18"></c:set>
    <c:out value="${user.age }"></c:out>
  </body>
</html>
2.3.<c:remove>标签
<c:remove>标签用于移除指定范围的变量。
<c:remove>标签的语法格式如下:
<c:remove var="变量名称" scope="JSP域范围"/>
var属性:要移除指定范围的变量名称。
scope属性:var属性指定的变量的范围(JSP域),默认是page。
下面是<c:set>标签的具体用法:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>remove.jsp</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">    
  </head>
  <body>
    <%
pageContext.setAttribute("a", "pageContext");
request.setAttribute("a", "session");
session.setAttribute("a", "session");
application.setAttribute("a", "application");
%>
<!-- 删除所有域中的name为a的数据 -->
<c:remove var="a"/>
<c:out value="${a }" default="none"/>
2.4.<c:if>标签
<c:if>标签用于实现Java语言中的if语句的功能。
<c:if>标签的语法格式如下:
<c:if test="条件" var="变量名称" scope="JSP域范围"></c:if>
test属性:测试的条件,用于判断标签体是否应该被执行。
var属性:将测试条件的结果值保存在该变量中,该变量的值类型为Boolean。
scope属性:var属性指定变量的JSP域范围,默认值为page。
下面是<c:if>标签的具体用法:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>if.jsp</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">    
  </head>
  <body>
    <c:set var="name" value="longestory"/>
<c:if test="${not empty name }" var="test" scope="session">
<c:out value="${name }"/>
</c:if>
<br>
<c:if test="${test }">
<c:out value="helloworld"></c:out>
</c:if>
  </body>
</html>
2.5.<c:choose>标签
<c:choose>标签、<c:when>标签和<c:otherwise>标签一起实现互斥条件的执行,类似于Java语言的if/else if/else语句。
<c:choose>标签、<c:when>标签和<c:otherwise>标签的语法格式如下:
<c:choose>
   <c:when test="条件"></c:when>
   <c:otherwise></c:otherwise>
</c:choose>
下面是<c:choose>标签、<c:when>标签和<c:otherwise>标签的具体用法:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>choose.jsp</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">    
  </head>
  <body>
     <c:set var="c" value="${param.score }"/>
<c:choose>
<c:when test="${c > 100 || c < 0 }">输入有误,请输入正确的成绩:0~100之间。</c:when>
<c:when test="${c >= 90 }">A</c:when>
<c:when test="${c >= 80 }">B</c:when>
<c:when test="${c >= 70 }">C</c:when>
<c:when test="${c >= 60 }">D</c:when>
<c:otherwise>E</c:otherwise>
</c:choose>
  </body>
</html>
2.6.<c:url>标签
<c:url>标签使用正确的URL重写规则构造一个URL。
<c:url>标签的语法格式如下:
<c:url value="url路径" var="变量名称" scope="JSP域范围"></c:url>
value属性:要处理的URL。
var属性:将处理的URL保存在该变量中,该变量的类型为String。
scope属性:var属性指定变量的JSP域范围,默认值为page。
下面是<c:url>标签的具体用法:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>url.jsp</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">    
  </head>
  <body>
     <a href="<c:url value='/servlet/AServlet'/>">链接1</a><br/>
<c:url value="/servlet/AServlet" var="url" scope="request">
<c:param name="username" value="longestory" />
<c:param name="password" value="123" />
</c:url>
<a href="${requestScope.url }">链接2</a>
  </body>
</html>
2.7.<c:forEach>标签
<c:forEach>标签用于对包含了多个对象的集合进行迭代,重复执行它的标签体,或者重复迭代固定的次数。
<c:forEach>标签的语法格式如下:
<c:forEach var="变量名称" begin="起始位置" end="截至位置" step="步长" items="集合对象" varStatus="迭代状态"></c:forEach>
var属性:用于迭代的变量名称。
begin属性:指定迭代的起始位置。
end属性:指定迭代的截至位置。
step属性:迭代的步长,默认的步长是1。
items属性:要迭代的集合对象。
varStatus属性:要迭代的状态,可以获取迭代过程中的一些状态。
对于<c:forEach>标签的实际用法,大体分为两种:
循环变量,指定开始和结束位置(计数):
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>foreach.jsp</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">    
  </head>
  <body>
    <c:forEach var="i" begin="1" end="10">
    ${i }<br/>
    </c:forEach>
    <br/>
    <c:set var="sum" value="0"/>
    <c:forEach var="i" begin="1" end="100">
    <c:set var="sum" value="${sum + i }"/>
    </c:forEach>
    sum = ${sum }
  </body>
</html>
循环遍历集合,其中包含数组、List或Map集合等:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>foreach.jsp</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">    
  </head>
  <body>
    <%
    String[] arr = {"one", "two", "three"};
    pageContext.setAttribute("arr", arr);
    List<String> list = new ArrayList<String>();
    list.add("a");
    list.add("b");
    list.add("c");
    pageContext.setAttribute("abc", list);
   
    Map<String,String> person = new LinkedHashMap<String,String>();
    person.put("name", "zhangSan");
    person.put("age", "23");
    person.put("sex", "male");
   
    pageContext.setAttribute("p", person);
    %>
    <c:forEach items="${arr }" var="str">
    ${str }<br/>
    </c:forEach>
    <br/>
    <c:forEach items="${abc }" var="str">
${str }<br/>
    </c:forEach>
    <br/>
    <c:forEach items="${p }" var="entry">
    ${entry.key } = ${entry.value }<br/>
    </c:forEach>
  </body>
</html>
在迭代中通过varStatus属性获取迭代中的状态。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>foreach.jsp</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">    
  </head>
  <body>
    <c:forEach items="${arr }" var="str" varStatus="vs">
    first: ${vs.first }, last: ${vs.last }, count: ${vs.count }, index: ${vs.index }, current: ${vs.current }<br/>
    </c:forEach>
  </body>
</html>


JSTL国际化

name=xiaofeng
info=Current user{0}:Welcome to use our system//程序跑的时候动态塞




name=\u5c0f\u950b
info=\u5f53\u524d\u7528\u6237{0}:\u6b22\u8fce\u4f7f\u7528\u672c\u7cfb\u7edf


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<fmt:setLocale value="zh_CN"/>
<fmt:bundle basename="info">
<fmt:message key="name" var="userName"/>
</fmt:bundle>
<h2>姓名:${userName }</h2>
<fmt:bundle basename="info">
<fmt:message key="info" var="infomation">
<fmt:param value="<font color='red'>小锋</font>"/>
</fmt:message>
</fmt:bundle>
<h2>信息:${infomation }</h2>
<hr/>
<fmt:setLocale value="en_US"/>
<fmt:bundle basename="info">
<fmt:message key="name" var="userName"/>//读取的name放入userName中
</fmt:bundle>
<h2>姓名:${userName }</h2>
<fmt:bundle basename="info">
<fmt:message key="info" var="infomation">
<fmt:param value="<font color='red'>小锋</font>"/>
</fmt:message>
</fmt:bundle>
<h2>信息:${infomation }</h2>
</body>
</html>


package com.java1234.model;


public class People {


private int id;
private String name;
private int age;



public People(int id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
public People() {
super();
// TODO Auto-generated constructor stub
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}


}




4.1.什么是国际化
如果一个系统或软件在某个国家或地区使用时,采用该国家或地区的语言、数字、货币和日期等习惯,将这种方式称之为资源本地化。开发系统或软件时,可以支持多个国家或地区的本地化应用,就可以叫做资源国际化。
所谓资源国际化,并不是简单提供几套不同语言的软件系统就能解决的,是一个很复杂的问题。而Java提供了资源绑定ResourcesBundle、地区Locale、时区TimeZone等支持资源国际化。资源国际化有两个常用的术语I18N与I10N。
I18N即资源国际化,全称为Internationalization,因为首字母I与末字母N之间共18个字母,又称I18N。通俗地讲,资源国际化就是要让这个系统或软件使用国际环境,如语言、数字、货币和日期等。
I10N为资源本地化,全称为Localization,因为首字母I与末字母N之间共10个字母,又称I10N。资源本地化就是要让这个系统或软件使用当地环境,如语言、数字、货币和日期等。
4.2.如何国际化
让一个系统或软件实现本地化不难,但想要实现国际化还是有一些难度的。下面先来学习Java中提供的实现国际化功能的方式,具体内容如下:
在Web工程的“src”根目录下创建国际化资源文件。
国际化默认的资源文件命名方式为“资源文件名称.properties”。
name=default longestory
如果创建对应本地化资源文件的话,命名方式为“资源文件名称_语言代码_国家代码.properties”。下面分别为英文资源文件和中文资源文件,其中中文资源文件的编码为ISO-8859-1。
name=longestory
name=\u9F99\u54E5\u6709\u8BDD\u8BF4
创建一个Java文件,用于读取国际化资源文件,进行测试。
public class ResourceBundleTest {
@Test
// 与访问用户默认的语言和国家匹配
public void demo(){
// 通过ResourceBundle类的getBundle(默认国际化资源文件名称)方法读取国际化资源文件
ResourceBundle bundle = ResourceBundle.getBundle("info");
// 通过ResourceBundle对象的的getString(key)获取value
String value = bundle.getString("name");
// 测试打印
System.out.println(value);
}
}
右键运行该Java类,查看控制台打印信息。(当前计算机使用的语言是中文,国家是中国)
果想要获取指定国家和语言的国际化资源文件,可以如下来完成。
创建一个Java文件,用于读取国际化资源文件,进行测试。
public class ResourceBundleTest {
@Test
public void demo2(){
// 通过ResourceBundle类的getBundle(默认国际化资源文件名称)方法读取国际化资源文件
ResourceBundle bundle = ResourceBundle.getBundle("info",Locale.US);
// 通过ResourceBundle对象的的getString(key)获取value
String value = bundle.getString("name");
// 测试打印
System.out.println(value);
}
}
4.3.期国际化
除了文本信息需要国际化以外,日期也需要国际化,可以使用Java提供的java.text.DateFormat类来完成。首先,来参考一下Java提供的API文档,需要用到DateFormat类的哪些方法:
创建一个Java类,用于获取日期和时间等内容的国际化方式
public class DateFormatTest {
@Test
public void demo(){
Date date = new Date();
/*
* getDateInstance(int style,Locale local):
*  * 获得日期 formatter,该 formatter 具有给定语言环境的给定格式化风格.
*  * style参数:表示使用的日期格式化风格,常用的选项有FULL、LONG、MEDIUM、SHORT.
*  * local参数:指定使用的语言环境.
*/
DateFormat dateFormat1 = DateFormat.getDateInstance(DateFormat.FULL, Locale.CHINA);
System.out.println("日期国际化:"+dateFormat1.format(date));
/*
* getTimeInstance(int style,Locale local)
*  * 获得时间 formatter,该 formatter 具有给定语言环境的给定格式化风格.
*  * style参数:表示使用的时间格式化风格,常用的选项有FULL、LONG、MEDIUM、SHORT.
*  * local参数:指定使用的语言环境.
*/
DateFormat dateFormat2 = DateFormat.getTimeInstance(DateFormat.LONG, Locale.CHINA);
System.out.println("时间国际化:"+dateFormat2.format(date));
/*
* getDateTimeInstance(int dateStyle, int timeStyle, Locale locale)
*  * 获得日期/时间 formatter,该 formatter 具有给定语言环境的给定格式化风格.
*  * dateStyle参数:表示使用的日期格式化风格,常用的选项有FULL、LONG、MEDIUM、SHORT.
*  * timeStyle参数:表示使用的时间格式化风格,常用的选项有FULL、LONG、MEDIUM、SHORT.
*  * local参数:指定使用的语言环境.
*/
DateFormat dateFormat3 = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT, Locale.CHINA);
System.out.println("日期和时间同时国际化:"+dateFormat3.format(date));
}
}
创建一个Java类,用于获取日期和时间等内容的国际化方式。
public class NumberFormatTest {
@Test
public void demo1(){
double i = 3.1415926;

NumberFormat numberFormat1 = NumberFormat.getIntegerInstance(Locale.CHINA);
System.out.println("指定语言环境的整数格式为:"+numberFormat1.format(i));

NumberFormat numberFormat2 = NumberFormat.getNumberInstance(Locale.CHINA);
System.out.println("指定语言环境的通用数字格式为:"+numberFormat2.format(i));

NumberFormat numberFormat3 = NumberFormat.getCurrencyInstance(Locale.CHINA);
System.out.println("指定语言环境的货币格式为:"+numberFormat3.format(i));

NumberFormat numberFormat4 = NumberFormat.getPercentInstance(Locale.CHINA);
System.out.println("指定语言环境的百分比格式为:"+numberFormat4.format(i));
}
}
4.5.动态文本国际化
之前实现了文本信息的国际化,可以使用占位符实现固定文本实现动态变化。具体实现方式参考如下内容:
public class MessageFormatTest {
@Test
public void demo(){
/*
* 作为错误信息的显示
* String msg1 = "用户名不能为空";
* String msg2 = "密码不能为空";

* 所有不能为空提示信息完全一样,区别是字段名称
*/
String pattern = "{0}不能为空";


// 通过MessageFormat 将信息替换到占位符中
String s1 = MessageFormat.format(pattern, "用户名");
String s2 = MessageFormat.format(pattern, "密码");
System.out.println(s1);
System.out.println(s2);
当然,占位符不仅可以使用一个,多个占位符也是允许的,参考如下内容:
public class MessageFormatTest {
@Test
public void demo(){
String pattern = "{0}的长度必须在 {1}到{2}位数之间";
System.out.println(MessageFormat.format(pattern, "用户名", 3, 10));
}
}
动态文本信息的国际化还具有很多高级用法,例如如下案例:
public class MessageFormatTest {
@Test
public void demo() {
// 动态文本高级应用
String s = "At {0,time,short} on {0,date,medium}, a hurricance destroyed {1,number,integer} houses and caused {2,number,currency} of damage";
// 第一个参数 日期对象12:30 pm on jul 3,1998
Calendar calendar = Calendar.getInstance();// 日历类
// 所有日期月份从0开始
calendar.set(1998, 6, 3, 12, 30, 0);
Date date = calendar.getTime();
// 第二个参数 99
int n = 99;
// 第三个参数 $1000000
int m = 1000000;


// 指定locale 是美国
MessageFormat messageFormat = new MessageFormat(s, Locale.US);
System.out.println(messageFormat.format(new Object[] { date, n, m }));
}
}
4.6.国际化案例
上述国际化内容都只是利用测试类完成国际化逻辑,下面利用国际化内容完成登录页面的国际化功能。具体的操作步骤如下:
在Web工程的“src”根目录下创建国际化资源文件。
info.properties
info = default form
username = default username
password = default password
submit = default submit
info_en_US.properties
info = form
username = username
password = password
submit = submit
info_zh_CN.properties
info=\u767B\u9646\u9875\u9762
username=\u7528\u6237\u540D
password=\u5BC6\u7801
submit=\u767B\u9646
创建一个JSP页面用于显示登录信息,并实现国际化。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>login.jsp</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">    
  </head>
  <body>
    <%
    // 接收参数locale,该参数传递国际化环境,例如zh_CN.
String localeinfo = request.getParameter("locale");
// 创建ResourceBundle对象
ResourceBundle bundle = null;
// 判断国际化环境内容是否为空
if(localeinfo == null){
// 如果为空,使用默认的国际化资源文件内容.
bundle = ResourceBundle.getBundle("info");// 使用默认
}else{
// 如果不为空,将国际化环境参数,拆分成语言和国家.
String[] arr = localeinfo.split("_");
if(arr.length>1){
// 表示国际化环境参数包含语言和国家内容
bundle = ResourceBundle.getBundle("info",new Locale(arr[0],arr[1]));
}else if(arr.length == 1){
// 表示国际化环境参数只包含语言内容
bundle = ResourceBundle.getBundle("info",new Locale(arr[0]));
}
}
%>
<h1><%=bundle.getString("info") %></h1>
<form action="#" method="post">
<%=bundle.getString("username") %> <input type="text" name="username" /><br/>
<%=bundle.getString("password") %> <input type="password" name="password" /><br/>
<input type="submit" value="<%=bundle.getString("submit") %>" />
</form>
  </body>
</html>
4.7.JSTL国际化标签
上述登录案例除了使用在JSP页面嵌入Java代码实现以外,还可以通过JSTL标签库的I18N标签库来实现。具体实现方式如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>login.jsp</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">    
  </head>
  <body>
<!-- 设置指定国家locale -->
<fmt:setLocale value="${param.locale}"/>
<!-- 创建ResourceBundle -->
<!-- 将ResourceBundle对象保存 page范围 bundle 属性中 -->
<fmt:setBundle basename="info" var="bundle" scope="page"/>
<!-- 显示form表单 -->
<h1><fmt:message bundle="${bundle}" key="info" /> </h1>
<form action="xxxx" method="post">
<fmt:message bundle="${bundle}" key="username" />  <input type="text" name="username" /><br/>
<fmt:message bundle="${bundle}" key="password" />  <input type="password" name="password" /><br/>
<input type="submit" value="<fmt:message bundle="${bundle}" key="submit" /> " />
</form>
  </body>
</html>
JSTL标签库的I18N标签库除了以上标签外,也提供了日期和数字的格式化功能。具体内容参考如下内容:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>fmt.jsp</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">    
  </head>
  <body>
    <%
    pageContext.setAttribute("date", new Date());
    pageContext.setAttribute("num", "3");
    %>
    <fmt:formatDate value="${date }" pattern="yyyy-MM-dd HH:mm:ss"/><br/>
    <fmt:formatNumber value="${num }" pattern="#.##" /><br/>
    <fmt:formatNumber value="${num }" pattern="0.00" /><br/>
  </body>
</html>