菜单 学习猿地 - LMONKEY

JAVAWEB开发之JSTL标签库的使用、 自己定义EL函数、自己定义标签(带属性的、带标签体的)

ebichu profile image ebichu ・1 min read

JSTL

 JSTL简单介绍:
JSTL的全称:JSP Standard Tag Library,JSP标准标签库
JSTL的作用:
  提供给Java Web开发者一个标准通用的标签函数库
  和EL来代替传统直接在页面上嵌入Java程序(Scripting)的做法,以提高程序可读性、维护性和方便性
JSTL的版本号:
   JSTL的主要版本号是1.0、1.1和1.2(差别不大)
   1.0版本号EL表达式还没有纳入官方规范
   1.1和1.2版本号EL表达式已经纳入了官方规范

JSTL1.1 下载对应的jar包
JSTL的下载
   JSTL主要由Apache组织的Jakarta Project实现
   http://tomcat.apache.org/taglibs/standard/
   容器必须支持Servlet2.4且JSP2.0以上的版本号
   JavaEE1.4
JSTL导入jar包
   解压缩后将lib中的jstl.jar、standard.jar 拷贝到WEB应用程序的WEB-INF\lib下


JSTL标签库
  • 核心标签库(core)---c(重点)
  • XML(x:操作xml的标签库)
  • SQL(sql标签库)
  • FMT(fmt:国际化标签库)
  • JSTL函数(EL函数)el
JSTL高速入门
   导入jar包(jstl.jar和standard.jar)
         当中jstl.jar是编译后的Java类文件,standard.jar定义的是标准接口
   新建JSP的页面
        在页面中引入核心标签库
        <%@ taglib uri="http://java.sun.com/jsp/jstl/core"  prefix="c"  %>
   JSTL标签库关于导入版本号的问题
        http://java.sun.com/jsp/core    1.1或者1.2版本号(使用该版本号)
        http://java.sun.com/jstl/core     1.0版本号(不支持EL表达式

<c:out>标签

输出常量或者域范围中的变量(value属性,使用EL表达式)
输出默认值(default属性)
默认HTML标签不转义(escapeXml)
属性名 是否支持EL 属性类型 属性描写叙述
value true Object 指定要输出的内容
escapeXml true Boolean 指定是否将>、<、&、'、" 等
特殊字符进行HTML编码转换
后再进行输出。默认值是true。
default true Object 指定假设value属性的值为null时所输出的默认值
<!-- c:out 输出数据到浏览器 -->
<c:out value="Hello c out "></c:out>
Hello c out 
<!-- 输出一个变量 -->
<c:set var="m" value="10" scope="page"/>
<c:out value="${m}"></c:out>
${m }
<!-- 转义HTML 默认转义,通过设置escapeXml 为false 不进行转义-->
<c:out value="<a href='xxx'>link</a>" />
${fn:escapeXml("<a href='xxx'>link</a>") }
<!-- 同意输出默认值 ,假设city不存在,输出北京-->
<c:out value="${city}" default="北京"></c:out>
${empty city?"北京":city }
在WebRoot下新建jstl目录,在目录下新建out.jsp
实例代码例如以下:
<%@ 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>

<h4>传统方式</h4>
<%= "Hello" %>
<%
	int a = 10;
	request.setAttribute("name", "xy");
%>
<%= a %>


<h4>JSTL的方式 </h4>
<c:out value="Hello"></c:out>
<c:out value="${name }"></c:out>
<!-- "" -->
<c:out value="${ city }" default="北京"></c:out>
<c:out value="<a href='#'>超链接</a>" escapeXml="false"/>
<c:out value="<a href='#'>超链接2</a>" escapeXml="true"/>

</body>
</html>

<c:set>标签

  • 向4个域中存入值。(var value scope属性
  • 设置Web域中的java.util.Map 类型的属性对象或JavaBean类型的属性对象的属性(target  property  value属性
属性名 是否支持EL 属性类型 属性描写叙述
value true Object 用于指定属性
var false String 用于指定要设置的Web域属性的名称
scope false String 用于指定属性所在的Web域
target true Object 用于指定要设置属性的对象。这个对象必须是
JavaBean对象或java.util.Map对象
property true String 用于指定当前要为对象设置的属性名称

在WebRoot/jstl下新建set.jsp
代码例如以下:
<%@page import="cn.itcast.vo.User"%>
<%@ 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>

<h4>传统方式</h4>
<%
	pageContext.setAttribute("name", "10", pageContext.REQUEST_SCOPE);
	
%>

<%
	User user = new User();
	user.setUsername("美美");
	user.setPassword("123");
	request.setAttribute("user", user);
%>
${ user.username }

<h4>JSTL方式</h4>
<c:set var="i" value="10" scope="request" ></c:set>
${ i }

<c:set target="${ user }" property="username"  value="小凤"></c:set>
${ user.username }

</body>
</html>

<c:remove>标签

<c:remoive>标签用于删除各种Web域中的属性
其语法格式例如以下:
<c:remove  var="varName"  [scope="{page|request|session|application}"]>
 假设不设置,默认是pageContext域范围内查找删除值。
使用方法演示样例:
<%
request.setAttribute("age",20);
// 删除age
request.removeAttribute("age");
%>
<c:set var="age" value="20" scope="request"></c:set>
<c:remove var="age" scope="request"/>
在WebRoot/jstl文件夹下新建remove.jsp
 实例代码例如以下:
<%@ 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>

<h4>传统方式</h4>
<%
	request.setAttribute("name", "美美");
	request.removeAttribute("name");
%>

<c:set var="name" value="小凤" scope="page"></c:set>
${ name }

<c:remove var="name" scope="page"/>
${name }

</body>
</html>

<c:catch>标签

  • <c:catch>标签用于捕获嵌套在标签中的内容抛出的异常。其语法格式例如以下:<c:catch [var="varName"]> nested actions </c:catch>
  • var属性用于标识<c:catch>标签捕获的异常对象,它将保存在page这个web域中。
关键代码:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=gb2312" %>
<c:catch var="myex“ >
<%
10/0;
%>
</c:catch>
异常:<c:out value="${myex}" />  ${myex}<br />
异常 myex.getMessage:<c:out value="${myex.message}" /><br />
异常 myex.getCause:<c:out value="${myex.cause}" /><br />
异常 myex.getStackTrace:<c:out value="${myex.stackTrace}" />
在WebRoot/jstl下新建catch.jsp
 实例代码例如以下:
<%@ 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>

<h4>传统方式</h4>
<%
	try{
		
	}catch(Exception e){
		e.printStackTrace();
	}
%>

<h4>JSTL的方式</h4>
<c:catch var="e">
	<%
		int a = 10/0;
	%>
</c:catch>
${ e.message }

</body>
</html>


<c:if>标签

<c:if test=""> 标签能够构造简单的"if-then"结构的条件表达式
属性名 是否支持EL 属性类型 属性描写叙述
test true boolean 决定是否处理标签体中的内容的条件表达式
var false String 用于指定将test属性的运行结果保存到某个Web域中的某个属性的名称
scope false String 指定将test属性的运行结果保存到哪个Web域中
注意:没有<c:else>
在WebRoot/jstl下新建if.jsp
<%@ 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>

<h4>传统方式</h4>
<%
	int a = 10;
	if(a >= 10){
		out.print("a >= 10");
	}else{
		out.print("a < 10");
	}
%>

<h4>JSTL方式</h4>
<c:set var="i" value="10" scope="page"></c:set>
<c:if test="${ i ge 10 }" var="x" scope="page">
	i >= 10
</c:if>
<c:if test="${ i lt 10 }">
	i < 10
</c:if>

${ x }

</body>
</html>


<c:choose>

<c:choose>标签用于指定多个条件选择的组合边界。它必须与<c:when>和<c:otherwise>标签一起使用。

使用<c:choose>,<c:when>,<c:otherwise>三个标签,能够构造类似于"if-else if-else"的复杂条件推断结构

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=gb2312" %>
<c:set value="${param.count}" var="count“  /> pageContext(count,2)
<c:choose>
<c:when test="${count == 0}">
对不起,没有符合您要求的记录。
</c:when>
<c:otherwise>
符合您要求的记录共同拥有${count}条.
</c:otherwise>
</c:choose>
在WebRoot/jstl文件夹下新建choose.jsp
代码例如以下:
<%@ 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>

<h4>获取參数</h4>
<%= request.getParameter("username") %>

<h4>传统方式</h4>
<%
	int a = 10;
	if(a >= 10 ){
		out.print("a >= 10");
	}else if(a < 10){
		out.print("a < 10");
	}else{
		out.print("其它");
	}
%>

<h4>JSTL方式</h4>
<c:set var="i" value="10" scope="page"></c:set>
<c:choose>
	<c:when test="${ i ge 10 }">
		i >= 10
	</c:when>
	<c:when test="${ i lt 10 }">
		i < 10
	</c:when>
	<c:otherwise>
		其它
	</c:otherwise>
</c:choose>
	

</body>
</html>

<c:forEach>标签

<c:forEach>标签用于对一个集合对象中的元素进行循环迭代操作。或者按指定的次数反复迭代运行标签体中的内容

属性名 是否支持EL 属性类型 属性描写叙述
var false String 指定将当前迭代到的元素保存到page这个域中的属性名称
varStatus false String 记住用于保存迭代信息的对象
items true 不论什么支持的类型 将要迭代的集合对象
begin true int 假设指定items属性,就从集合中的第begin个元素開始进行迭代
。begin的索引值从0開始编号。假设没有指定items属性,就从
begin指定的值開始迭代。直到end值时结束迭代
end true int 与begin属性类似
step true int 指定迭代的步长,即迭代因子的迭代增量

<c:forEach>遍历集合
遍历数组或者集合:
   var:代表遍历的每个元素
   items:要迭代的集合对象
   获取遍历的内容:${ xxx }
遍历Map集合:
   var:代表key与value的关系entry
   items:要迭代的map集合
   获取遍历的内容:${ xxx.key } ----${ xxx.value }
遍历对象集合:
   var:代表遍历的每个对象
   items:要迭代的集合
   获取遍历的内容: ${ xxx.对象的属性 }

<c:forEach>迭代数据

从1遍历到10:
   var:定义变量
   begin:从哪開始
   end:到哪结束
   step:迭代步长(相当于x+=step)
计算从1加到10的和:
   定义变量sum。值为0
   通过forEach循环1到10,每循环一次加到还有一个变量中
   在循环中间定义变量。每次计算到该变量中
<c:set var="sum" value="0" scope="page"></c:set>
<c:forEach begin="1" end="10" step="1" var="i">
     <c:set var="sum" value="${sum + i}" scope="page"></c:set>
</c:forEach>
${sum }

varStatus属性:
记录迭代相关的信息:
属性 类型 意义
index number 如今指到成员的索引
count number 总共指到成员的总数
first boolean 如今指到的成员是否是第一个成员
last boolean 如今指到的成员是否是最后一个成员
遍历10到100的偶数,每到第三个数,显示红色
<c:forEach begin="10" end="100" step="2" var="i" varStatus="status">
<c:if test="${status.count % 3 == 0}">
<font color="red">${i }</font>
</c:if>
<c:if test="${status.count % 3 != 0}">
<font color="blue">${i }</font>
</c:if>
</c:forEach>

在WebRoot/jstl文件夹下新建forEach.jsp
实例代码例如以下:
<%@page import="cn.itcast.vo.User"%>
<%@page import="java.util.HashMap"%>
<%@page import="java.util.Map"%>
<%@page import="java.util.ArrayList"%>
<%@page import="java.util.List"%>
<%@ 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>

<h4>遍历数组</h4>
<%
	String [] arrs = {"美美","小凤","芙蓉","小苍"};
	request.setAttribute("arrs", arrs);
%>
<!-- for(String s : arrs){ }  -->
<c:forEach var="s" items="${ arrs }">
	${ s }
</c:forEach>

<h4>遍历集合</h4>
<%
	List<String> list = new ArrayList<String>();
	list.add("美美");
	list.add("小凤");
	list.add("芙蓉");
	list.add("小泽");
	request.setAttribute("list", list);
%>
<c:forEach var="s" items="${ list }">
	${ s }
</c:forEach>

<h4>遍历Map集合</h4>
<%
	Map<String,String> map = new HashMap<String,String>();
	map.put("aa", "美美");
	map.put("bb", "小凤");
	map.put("cc", "芙蓉");
	request.setAttribute("map", map);
%>
<c:forEach var="entry" items="${ map }">
	${ entry.key } -- ${ entry.value }
</c:forEach>

<h4>遍历对象的集合</h4>
<%
	List<User> uList = new ArrayList<User>();
	uList.add(new User("美美","123"));
	uList.add(new User("小风","234"));
	uList.add(new User("芙蓉","345"));
	request.setAttribute("uList", uList);
%>
<c:forEach var="user" items="${ uList }">
	${ user.username } -- ${ user.password }
</c:forEach>


<h4>迭代数据</h4>
<h4>迭代从1到10</h4>
<c:forEach var="i" begin="1" end="10" step="2">
	${ i }
</c:forEach>


<h4>计算从1加到100的和</h4>
<c:set var="sum" value="0" scope="page"></c:set>
<c:forEach var="i" begin="1" end="100" step="1" varStatus="status">
	<c:set var="sum" value="${ sum + i }"></c:set>
</c:forEach>
${ sum }


<h4>遍历10到100的偶数,每到第3个数,显示红色</h4>
<c:forEach var="i" begin="10" end="100" step="2" varStatus="status">
	<c:choose>
		<c:when test="${ status.first }">
			<font color="blue">${ i }</font>
		</c:when>
		<c:when test="${ status.count % 3 eq 0 }">
			<font color="red">${ i }</font>
		</c:when>
		<c:otherwise>
			${ i }
		</c:otherwise>
	</c:choose>
</c:forEach>

</body>
</html>


 <c:forTokens>

用来切分字符串
名称 说明 EL 类型 必须 默认值
var 用来存放如今指到的成员 N String
items 被迭代的字符串 Y String
delims 定义用来切割字符串的字符 N String
varStatus 用来存放如今指到的相关成员信息 N String
begin 開始的位置 Y int 0
end 结束的位置 Y int 最后一个成员
<c:set var="s" value="aaa,bbb,ccc" scope="page"></c:set>
<c:forTokens items="${s}" delims="," var="e">
${e }
</c:forTokens>
语法格式:
<c:forTokens 
items=要切分的字符串
delims=按着什么格式切分
var=定义变量
[varStatus="varStatusName"] 
[begin="begin"] 
[end="end"] 
[step="step"]>
 //body内容
</c:forTokens>
在WebRoot/jstl文件夹下新建forTokens.jsp
代码例如以下:
<%@ 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>

<h4>分隔字符串</h4>
<c:set var="i" value="aa,bb,cc" scope="page"></c:set>
<c:forTokens items="${i }" delims="," var="x">
	${ x }
</c:forTokens>

</body>
</html>

<c:param>标签

  • 在JSP页面进行URL的相关操作时。常常要在URL地址后面附加一些參数。<c:param>标签能够嵌套在<c:import>、<c:url>或<c:redirect>标签内,为这些标签所使用的URL地址附加參数。
  • <c:param>标签在为一个URL地址附加參数时。将自己主动对參数值进行URL编码,比如:假设传的參数值为“中国”。则将其转换为“%d6%d0%b9%fa”后再附加到URL地址后面,这也就是使用<c:param>标签的最大优点
  • 演示样例:<c:param name="name"  value="value" />

<c:import>标签

名称 说明 EL 类型 必须 默认值
url 一文件被包括的地址 Y String
context 项目虚拟路径 Y String
var 储存被包括的文件的内容(以String类型存入) Y String
scope var变量的JSP范围 N String page
charEncoding 被包括文件的内容的编码方式 Y String
varReader 储存被包括的文件的内容(以Reader类型存入) N String
<!-- 引入foreach.jsp 效果类似包括-->
<c:import url="/jstl/foreach.jsp" context="/day8"></c:import>
<hr/>
<!-- 引入不显示,将内容保存还有一个变量中 -->
<c:import url="/jstl/foreach.jsp" context="/day8" var="content" scope="page"></c:import>
${content }
<c:import url="http://java.sun.com" >
<c:param name="test" value="1234" />
</c:import>

在WebRoot/jstl/下新建 import.jsp(包括choose.jsp 并在choose.jsp 中获取參数)
实例代码例如以下:
<!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>

<h4>JSTL方式</h4>
<c:import url="/jstl/choose.jsp" context="/day13" var="i" scope="page">
	<c:param name="username" value="meimei"></c:param>
</c:import>

${ i }


</body>
</html>

<c:url>标签

<c:url>标签用于在JSP页面中构造一个URL地址。其主要目的是实现URL重写。URL重写就是将会话标识以參数形式附加在URL地址后面。

(类似于Session追踪 尤其是当浏览器禁用cookie后,就是说实现了session追踪的功能)

属性名 是否支持EL 属性类型 属性描写叙述
value true String 指定要构造的URL
var false String 指定将构造出的URL结果保存到Web域中的属性名称
scope false String 指定将构造出的URL结果保存在哪个域中

在WebRoot/jstl/下新建url.jsp 
<%@ 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>

<h4>JSTL方式</h4>
<c:url var="i" value="/jstl/choose.jsp" scope="request" context="/day13">
	<c:param name="username" value="xiaofeng"></c:param>
</c:url>
<c:set var="s" value="刘勋" scope="session"></c:set>
<a href="${ i }">choose</a> <br>
i= ${i } <br>
<%
    String url = "/day12/index.jsp";
    url = response.encodeURL(url);
%>

<!-- 将/day8/index.jsp 进行url重写。保存page范围 myurl中 -->
<c:url value="/index.jsp" context="/day13" var="myurl" scope="page" />

url=  <%=url %> <br>
myurl= ${myurl } <br>

<!-- 通过c:url 结合 c:param 对中文完毕URL编码 -->
<c:url value="/login" context="/day13" var="myurl2" scope="page">
	<c:param name="username" value="张三"></c:param>
</c:url>
myurl2= ${myurl2 } <br>

</body>
</html>

改动choose.jsp 例如以下:
<%@ 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="${s }"></c:out>
<h4>获取參数</h4>
<%= request.getParameter("username") %>

<h4>传统方式</h4>
<%
	int a = 10;
	if(a >= 10 ){
		out.print("a >= 10");
	}else if(a < 10){
		out.print("a < 10");
	}else{
		out.print("其它");
	}
%>

<h4>JSTL方式</h4>
<c:set var="i" value="10" scope="page"></c:set>
<c:choose>
	<c:when test="${ i ge 10 }">
		i >= 10
	</c:when>
	<c:when test="${ i lt 10 }">
		i < 10
	</c:when>
	<c:otherwise>
		其它
	</c:otherwise>
</c:choose>
	

</body>
</html>
禁用浏览器的cookie后。执行例如以下:

点击choose跳转到choose.jsp

<c:redirect>标签

<c:redirect>标签用于实现请求重定向
属性名 是否支持EL 属性类型 属性描写叙述
url true String 指定要转发或重定向到的目标资源的URL地址
context true String 当要使用相对路径重定向到同一个server下的其它WEB应用程序中的
资源时,context属性指定其它WEB应用程序的名称

注意:假设重定向第三方的站点时要使用绝对路径(不能再使用Context)
<%
// 曾经重定向
// response.sendRedirect("/day12/index.jsp");
%>
<c:redirect url="/index.jsp" context="/day12"></c:redirect>

在WebRoot/jstl下新建redirect.jsp
<%@ 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>

<h4>JSTL方式</h4>

<c:redirect url="/jstl/choose.jsp" context="/day13">
	<c:param name="username" value="furong"></c:param>
</c:redirect>

</body>
</html>

 EL函数库

JSTL中的经常使用EL函数

EL函数是用来操作字符串的
因为在JSP页面中显示数据时,常常须要对显示的字符串进行处理,SUN公司针对一些常见处理定义了一套EL函数库供开发人员使用。

这些EL函数在JSTL开发包中进行描写叙述。因此在JSP页面中使用SUN公司的EL函数库。须要导入JSTL开发包,并在页面中导入EL函数库。例如以下所看到的:
  在页面中使用JSTL定义的EL函数:
  <%@taglib  uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"  %>
 (能够在fn.tld文件里查看)

 fn:toLowerCase 

fn:toLowerCase函数将一个字符串中包括的全部字符转换为小写形式,并返回转换后的字符串。它接收一个字符串类型的參数,比如:
  fn:toLowerCase("Www.IT315.org")的返回值为字符串"www.it315.org"
  fn.toLowerCase("") 的返回值为空字符串

fn:toUpperCase

fn:toUpperCase函数将一个字符串中包括的全部字符转换为大写形式,并返回转换后的字符串,它接收一个字符串类型的參数。比如:
  fn:toUpperCase("www.IT315.org")的返回值为字符串"WWW.IT315.ORG"
  fn:toUpperCase("")的返回值为空字符串

fn:trim

fn:trim函数删除一个字符串的首尾的空格,并返回删除空格后的结果字符串,它接收一个字符串类型的參数。须要注意的是,fn:trim函数不能删除字符串中间位置的空格
 比如:fn:trim("   www.it3 15.org ")的返回值字符串是"www.it 315.org"

fn:length

    fn:length函数返回一个集合或数组大小,或返回一个字符串中包括的字符的个数。返回值是int类型。fn:length函数接收一个參数。这个參数能够是<c:forEach>标签的items属性支持的不论什么类型。包括随意类型的数组、java.util.Collection、java.util.Iterator、java.util.Enumeration、java.util.Map等类的实例对象和字符串。
   假设fn:length函数的參数为null或者是元素个数为0的集合或数组对象。则函数返回0。假设參数是空字符串,则函数返回0;

fn:split

   fn:split函数以指定字符串作为分隔符,将一个字符串切割成数组并返回这个字符串数组。
   fn:split函数接收两个字符串类型的參数,第一个參数表示要切割的字符串。第二个參数表示作为分隔符的字符串。
   比如:fn:split("www.it315.org",".")[1]的返回值为字符串"it315"

fn:join

fn:join函数以一个字符串作为分隔符,将一个字符串数组中的全部元素合并为一个字符串并返回合并后的结果字符串。fn:join函数接收两个參数。第一个參数是要操作的字符串数组,第二个參数是作为分隔符的字符串。
假设fn:join函数的第二个參数是空字符串。则fn:join函数的返回值直接将元素连接起来。比如:
 如果stringArray是保存在Web域中的一个属性,它表示一个值为{"www","it315","org"}的字符串数组。则fn:join(stringArray,".")返回字符串"www.it315.org"
fn:join(fn:split("www,it315,org",","),".") 的返回值为字符串"www.it315.org"

fn:indexOf

fn:indexOf 函数返回指定字符串在一个字符串中第一次出现的索引值,返回值为int类型。

fn:indexOf函数接收两个字符串类型的參数。假设第一个參数字符串中包括第二个參数字符串,那么无论第二个參数字符串在第一个參数字符串中出现几次。fn:indexOf函数总是返回第一次出现的索引值;假设第一个參数中不包括第二个參数。则fn:indexOf函数返回-1。假设第二个參数为空字符串,则fn:indexOf函数总是返回0。

比如:fn:indexOf("www.it315.org","t3") 的返回值为5

fn:contains

    fn:contains函数检測一个字符串中是否包括指定的字符串,返回值为布尔类型。

fn:contains函数在比較两个字符串是否相等时是大写和小写敏感的。

    fn:contains函数接收两个字符串类型的參数。假设第一个字符串中包括第二个參数字符串返回true,否则返回false。假设第二个參数的值为空字符串。则fn:contains函数总是返回true。实际上,fn:contains(string,substring)等价于fn:indexOf(string,sunstring)!= -1
忽略大写和小写的EL函数:fn:containsIgnoreCase

fn:startsWith

fn:startsWith 函数用于检測一个字符串是否以指定的字符串開始的,返回值为布尔类型。
fn:startsWith 函数接收两个字符串类型的參数,假设第一个參数字符串以第二个參数字符串開始,则函数返回true,否则函数返回false。

假设第二个參数为空字符串。则fn:startsWith函数总是返回true。比如:

fn:startsWith("www.it315.org","it315")的返回值为false
与之相应的EL函数:fn:endsWith

fn:replace

fn:replace函数将一个字符串中包括的指定字符串替换为其它的指定字符串,并返回替换后的结果字符串。fn:replace("www it315 org"," ",".")的返回值为字符串"www.it315.org"

fn:substring

fn:substring 函数用于截取一个字符串的子字符串并返回截取到的子字符串。

fn:substring函数接收三个參数,第一个參数是用于指定要操作的源字符串。第二个參数是用于指定截取子字符串開始的索引值,第三个參数是用于指定截取子字符串结束的索引值,第二个參数和第三个參数都是int类型,其值都从0開始比如:

fn:substring("www.it315.org",4,9)的返回值为字符串"it315"

fn:substringAfter

fn:substringAfter函数用于截取并返回一个字符串中的指定字符串第一次出现之后的子字符串。fn:substringAfter函数接收两个字符串类型的參数。第一个參数表示要操作的源字符串。第二个參数表示指定的子字符串。
fn:substringAfter("www.it315.org",".")的返回值为字符串"it315.org"
与之相应的EL函数为:fn:substringBefore

自己定义EL函数开发步骤

 EL自己定义函数开发与应用包含下面三个步骤:
编写一个Java类。方法必须是静态方法
在WEB-INF文件夹下新建一个tld的文件。
   没有标签的提示,复制http://java.sun.com/xml/ns/j2ee , 合并名称
   设置2.0,设置url和shortname
编写标签库描写叙述符(tld)文件。在tld文件配置自己定义函数
   使用function标签配置自己定义函数。
   使用name标签配置方法名(能够随意)
   使用function-class标签配置类的全路径
   使用function-signature 标签配置返回值类型(中间有空格)方法名称(參数类型)
在JSP页面中导入和自己定义函数

开发EL function注意事项

编写标签库描写叙述文件后。须要将它放置到<web应用>\WEB-INF文件夹中或WEB-INF文件夹下的除了classes和lib文件夹之外的随意子文件夹中。

TLD文件里的<uri>元素用指定该TLD文件的URI,在JSP文件里须要通过这个URI来引入该标签库描写叙述文件。

<function>元素用于描写叙述一个EL自己定义函数,当中:
   <name>子元素用于指定EL自己定义函数的名称。
   <funtion-class>子元素用于指定完整的Java类名
   <function-signature>子元素用于指定Java类中的静态方法的签名。方法签名必须指明方法的返回类型以及各个參数的类型。各个參数之间用逗号分隔。
实比例如以下:
在src下新建一个cn.itcast.el的包。在包内新建ElDemo1.java
代码例如以下:
package cn.itcast.el;

public class ElDemo1 {
	
	public static String sayHello(String name){
		return "hello "+name;
	}
	
}
在WebRoot/WEB-INF下新建myfn的tld文件 并进行配置:


配置后的代码例如以下:
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" 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">
 <tlib-version>1.0</tlib-version>
 <short-name>myfn</short-name>
 <uri>http://www.itcast.cn/1110/myfn</uri>
 
 <!-- 配置自己定义的EL函数 -->
 <function>
 	<!-- 配置方法名称 -->
 	<name>sayHi</name>
 	<!-- 方法所在的类 -->
 	<function-class>cn.itcast.el.ElDemo1</function-class>
 	<!-- 配置方法的签名 -->
 	<function-signature>java.lang.String sayHello(java.lang.String)</function-signature>
 </function>
 
</taglib>
在WebRoot根文件夹下新建el文件夹,在里面新建demo.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>

<%@ taglib uri="http://www.itcast.cn/1110/myfn" prefix="myfn" %>
    
<!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>

${ fn:length("abcdefg") }

${ fn:toUpperCase("abcdefg") }

${ myfn:sayHi("小风") }

</body>
</html>

自己定义标签

自己定义标签简单介绍

自己定义标签主要用于移除JSP页面中的Java代码。提高代码的复用性
使用自己定义标签移除jsp页面在奇偶那个的Java代码。仅仅须要完毕下面步骤:
  •  编写一个实现Tag接口的Java类(标签处理器)
  • 编写标签库描写叙述符(tld)文件,在tld文件里对标签处理器类描写叙述成一个标签
  • 參考Tomcat中example项目中的JSP部分
由于企业业务需求是多种多样的。所以常见开源框架仅仅能提供通用的Java代码功能。假设实现既定业务逻辑功能,须要自己定义标签。通过自己定义标签(简化复杂业务开发)


简单标签

因为传统标签使用三个标签接口来完毕不同的功能,显得过于繁琐,不利于标签技术的推广,SUN公司为减少标签技术的学习难度,在JSP2.0中定义了一个更为简单、便于编写和调用的SimpleTag接口来实现标签的功能。

实现SimpleTag接口的标签通常称为简单标签。

SimpleTag方法介绍
  • setJspContext方法:用于把JSP页面的pageContext对象传递给标签处理器对象。
  • setParent方法:用于把父标签处理器对象传递给当前标签处理器对象。

  • getParent方法:用于获得当前标签的父标签处理对象。

  • setJspBody方法:用于把代表标签体的JspFragment对象传递给标签处理器对象。即传入标签体缓存对象(封装了标签体内容)
  • doTag方法:用于完后全部标签逻辑,包含输出、迭代、改动标签体内容等。

    在doTag方法中能够抛出javax.servlet.jsp.SkipPageException异常。用于通知WEB容器不再运行JSP页面中位于结束标记后面的内容,这等效于在传统标签的doEndTag方法中返回Tag.SKIP_PAGE常量的情况。

简单标签库开发经常使用功能,实现SimpleTag接口标签类(SimpleTag JSP2.0 之后为了简化标签开发提供的)
编写简单的标签类,仅仅须要继承SimpleTagSupport类
  setJspContext 传入pageContext对象
  setParent 传入父标签对象
  setJSPBody 传入标签体缓存对象(封装了标签体内容)
  doTag (运行标签。在该方法中编写标签代码逻辑)
在setJSPBody方法中传入对象JSPFragment。该对象封装了标签体内容。控制标签体内容输出
最重要方法invoke(Writer out) 意义将标签体内容输出到指定字符输出流中。
注意:在简单标签库中<bodyContent>不能写JSP。而必须写scriptless

SimpleTag接口方法的运行顺序:

当web容器開始运行标签时,会调用例如以下方法完毕标签的初始化:
  • WEB容器调用标签处理器对象的setJspContext方法,将代表JSP页面的pageContext对象传递给标签处理器对象。
  • WEB容器调用标签处理器对象的setParent方法,将父标签处理器对象传递给这个标签处理器对象。注意,仅仅有在标签存在父标签的情况下。WEB容器才会调用这种方法。
  • 假设调用标签时设置了属性,容器将调用每一个属性相应的setter方法把属性值传递给标签处理器对象。

    假设标签的属性值是EL表达式。则WEB容器首先计算表达式的值。然后把值传递给标签处理器对象。

  • 假设简单标签有标签体。容器将调用setJSPBody方法把代表标签体的JspFragment对象传递进来。
 运行标签时:
  •  容器调用标签处理器的doTag() 方法,开发者在方法内通过操作JspFragment对象。就能够实现是否运行、迭代、改动标签体的目的。


JSPFragment类

(1)javax.servlet.jsp.tagext.JspFragment类是在JSP2.0中定义的。它的实例对象代表JSP页面中的一段符合JSP语法规范的JSP片段。这段JSP片段中不能包括JSP脚本元素
(2)WEB容器在处理简单标签的标签体时,会把标签体内容用一个JspFragment对象表示,并调用标签处理器对象的setJSPBody方法把JspFragment对象传递给标签处理器对象。JspFragment类中仅仅定义了两个方法,例如以下所看到的:
      getJspContext方法:用于返回代表调用页面的JspContext对象——pageContext
      public abstract void invoke(java.io.Writer  out) 输出标签内容
           用于运行JspFragment对象所代表的JSP代码片段
           參数out用于指定将JspFragment对象的运行结果写入到哪个输出流对象中,假设传递给參数out的值为null。则            将运行结果写入到JspContext.getOut()方法返回的输出流对象中。(简而言之,能够理解为写给浏览器)

   invoke方法具体解释

JspFragment.invoke方法是JspFragment最重要的方法。利用这种方法能够控制是否运行和输出标签体的内容、是否迭代运行标签体的内容或对标签体的运行结果进行改动后再输出。

比如:

  • 在标签处理器中假设没有调用JspFragment.invoke方法,其结果就相当于忽略标签体内容。
  • 在标签体处理器中反复调用JspFragment.invoke方法。则标签体内容会被反复运行;
  • 若想在标签处理器中改动标签体内容。仅仅需在调用invoke方法时指定一个可取出结果数据的输出流对象(比如:StringWriter)。让标签体的运行结果输出到该输出流对象中。然后从该输出流对象中取出数据进行改动后在输出到目标设备。就可以达到改动标签体的目的。
例:控制标签后的jsp页面是否运行
   doTag
       throw new SkipPageException
   TLD配置
     <tag>
       <name>demo2</name>
       <tag-class>simple.MyTag2</tag-class>
        <body-content>empty</body-content>
      </tag>  

自己定义标签入门

需求:自己定义标签<myc:print>在页面中输出hello
步骤一:编写标签类
       编写一个类,继承SimpleTagSupport
       重写两个方法,doTag()setJspContext(JspContext pc)
       通过JspContext 对象能够获取out对象向外输出内容
步骤二:提供tld文件进行配置
       通过<tag>标签配置自己定义标签
       配置标签名称<name>print</name>
       配置标签的类<tag-class>xxx.xxx.xxx</tag-class>
       配置标签体的内容<body-content>empty</body-content>
步骤三:在JSP页面中引入该标签库

 自己定义带有标签体的标签

需求:自己定义标签<myc:out>在页面中输出内容
步骤一:编写标签类
      编写一个类,继承SimpleTagSupport
      重写两个方法。doTag()setJspContext(JspContext pc)
      在doTag()中通过getJspBody()获取JspFragment标签体,调用invoke(null)
步骤二:提供tld文件进行配置
      通过<tag>标签配置自己定义标签
      配置标签名称<name>out</name>
      配置标签的类<tag-class>xxx.xxx.xxx</tag-class>
      配置标签体的内容<body-content>scriptless</body-content>
步骤三:在JSP的页面中引入该标签库

Body-content的配置

<body-content>元素的可选值有:
  • empty:不能有标签体内容
  • JSP:标签体内容能够是不论什么东西:EL、JSTL、<%= %>、<%%>,以及HTML;但不建议使用Java代码段,SimpleTag已经不再支持使用<body-content>JSP</body-content>
  • scriptless:标签体内容不能是Java代码段,但能够是EL、JSTL等。
  • tagdependent:标签体内容不做运算。由标签处理类自行处理,不管标签体内容是EL、JSP、JSTL,都不会做运算。

自己定义带有属性的标签

需求:自己定义标签<myc:if>在页面中输出内容
步骤一:编写标签类
     编写一个类,继承SimpleTagSupport类。

     提供页面的属性,设置成boolean类型。

并提供set方法。页面的属性与类中的属性名称必须同样。

     重写doTag()方法,推断属性是否为true。通过getJspBody()获取JspFragment标签体。调用invoke(null)
步骤二:提供tld文件进行配置
     通过<tag>标签配置自己定义标签
     配置标签名称<name>if</name>
     配置标签的类<tag-class>xxx.xxx.xxx</tag-class>
     配置标签体的内容<body-content>scriptless</body-content>
     配置属性<attribute>在属性中配置其它信息</attribute>
步骤三:在JSP页面中引入标签库

attribute的配置
(1)配置属性名称
       <name>test</name>
(2)属性是否是必须的
       <required>true</required>
(3)配置是否支持EL表达式
       <rtexprvalue>true</rtexprvalue>
(4)配置属性的类型
       <type>boolean</type>

在TLD中描写叙述标签属性attribute

元素名 是否必须指定 描写叙述
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类型。

默认是String

<tag>元素的<attribute>子元素用于描写叙述自己定义
标签的一个属性。自己定义标签所具有的每一个属性
都要相应一个<attribute>元素 。
<attribute>
<description>description</description>
<name>aaaa</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>ObjectType</type>
</attribute>
实比例如以下:
在WEB项目的src文件夹下新建cn.itcast.tag包。在包内新建三个标签实现类
TagDemo1.java (没有标签体的自己定义标签)
package cn.itcast.tag;

import java.io.IOException;

import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;

/**
 * 对外输出Hello
 * @author Administrator
 *
 */
public class TagDemo1 extends SimpleTagSupport{
	
	private PageContext pc;
	
	public void doTag() throws JspException, IOException {
		pc.getOut().write("Hello");
	}
	
	/**
	 * server默认先运行该方法
	 */
	public void setJspContext(JspContext pc) {
		this.pc = (PageContext) pc;
	}

}
TagDemo2.java (有标签体 处理标签体内容)
package cn.itcast.tag;

import java.io.IOException;
import java.io.StringWriter;

import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;

/**
 * 带有标签主体
 * @author Administrator
 *
 */
public class TagDemo2 extends SimpleTagSupport{
	
	private PageContext pc;
	
	public void doTag() throws JspException, IOException {
		JspFragment jf = getJspBody();
		StringWriter sw = new StringWriter();
		//通过invoke方法将标签体内容写入到參数Writer对象sw中
		jf.invoke(sw);
		// 获取标签体内容
		String content = sw.toString().toUpperCase();
		pc.getOut().print(content);
	}
	
	public void setJspContext(JspContext pc) {
		this.pc = (PageContext)pc;
	}
}
TagDemo3.java (有属性 有标签体的自己定义标签)
package cn.itcast.tag;

import java.io.IOException;

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

/**
 * 相似<c:if>标签,带有属性的
 * @author Administrator
 *
 */
public class TagDemo3 extends SimpleTagSupport{
	
	private boolean test;
	
	public void setTest(boolean test) {
		this.test = test;
	}
	
	public void doTag() throws JspException, IOException {
		if(test){
			getJspBody().invoke(null);
		}
	}
	
}

在WebRoot/WEB-INF 文件夹下新建myc.tld文件
配置内容例如以下:
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" 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">
 <tlib-version>1.0</tlib-version>
 <short-name>myc</short-name>
 <uri>http://www.itcast.cn/1110/myc</uri>
 
 <!-- 配置自己定义标签 -->
 <tag>
 	<!-- 配置标签名称 -->
 	<name>print</name>
 	<!-- 配置标签的类 -->
 	<tag-class>cn.itcast.tag.TagDemo1</tag-class>
 	<!-- 配置标签主体 -->
 	<body-content>empty</body-content>
 </tag>
 
 <!-- 配置自己定义标签 -->
 <tag>
 	<!-- 配置标签名称 -->
 	<name>out</name>
 	<!-- 配置标签的类 -->
 	<tag-class>cn.itcast.tag.TagDemo2</tag-class>
 	<!-- 配置标签主体 -->
 	<body-content>scriptless</body-content>
 </tag>
 
 <!-- 配置自己定义标签 -->
 <tag>
 	<!-- 配置标签名称 -->
 	<name>if</name>
 	<!-- 配置标签的类 -->
 	<tag-class>cn.itcast.tag.TagDemo3</tag-class>
 	<!-- 配置标签主体 -->
 	<body-content>scriptless</body-content>
 	<!-- 配置属性 -->
 	<attribute>
 		<!-- 配置属性名称 -->
 		<name>test</name>
 		<!-- 属性是否是必须的 -->
 		<required>true</required>
 		<!-- 是否支持EL表达式 -->
 		<rtexprvalue>true</rtexprvalue>
 		<!-- 属性的类型 -->
 		<type>boolean</type>
 	</attribute>
 </tag>
 
</taglib>
在WebRoot下新建tag目录。新建tag.jsp 測试自己定义标签内容
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<%@ taglib uri="http://www.itcast.cn/1110/myc" prefix="myc" %>    
<%@ 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>

<myc:print/>

<myc:out>
	liuxun1993
</myc:out>

<c:set var="i" value="10"></c:set>
<myc:if test="${ i eq 10 }">
	美美
</myc:if>


</body>
</html>
启动server。执行结果例如以下:



评论 (0)