语法
el.jsp
<%@page import="java.util.Date"%> <%@page import="com.atguigu.javaweb.Customer"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!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> <form action="el.jsp" method="post"> username: <input type="text" name="username" value="<%= request.getParameter("username") == null ? "" : request.getParameter("username")%>"/> <!-- EL 表达式的有点: 简洁! --> username: <input type="text" name="username" value="${param.username }"/> <input type="submit" value="Submit"/> </form> username: <%= request.getParameter("username") %> <br><br> <jsp:useBean id="customer" class="com.atguigu.javaweb.Customer" scope="session"></jsp:useBean> <jsp:setProperty property="age" value="12" name="customer"/> age: <% Customer customer2 = (Customer)session.getAttribute("customer"); out.print(customer2.getAge()); %> <br> age: <jsp:getProperty property="age" name="customer"/> <br> <br> <% application.setAttribute("time", new Date()); %> <a href="el2.jsp?score=89&name=A&name=B&name=C">To El2 Page</a> </body> </html>
下面都在el2.jsp中
可以使用点和中括号运算符
<!-- 1. EL 的 . 或 [] 运算符 --> age: ${sessionScope.customer["age"] } <%-- Customer customer = (Customer)session.getAttribute("customer"); out.print(customer.getAge()); --%> <% Customer customer = new Customer(); customer.setName("ATGUIGU"); session.setAttribute("com.atguigu.customer", customer); %> <br> <!-- 如果域对象中的属性名带有特殊字符, 则使用 [] 运算符会很方便. --> name: ${sessionScope["com.atguigu.customer"].name }
EL中的隐含对象,EL可以大大简化代码
<!-- 2. EL 中的隐含对象 --> <% Customer cust2 = new Customer(); cust2.setAge(28); request.setAttribute("customer", cust2); %> age: ${customer.age }
可以自动类型转换
上面的结果是加了11的数
下面的结果是字符串
<!-- 3. EL 可以进行自动的类型转换 --> score: ${param.score + 11} <br> score: <%= request.getParameter("score") + 11 %> <br>
<!-- 4. 隐含对象之与范围相关的: pageScope, requestScope, sessionScope, applicationScope -->
time: ${applicationScope.time.time }
<%--
<%= application.getAttribute("time") %>
--%>
<!-- 5. 与输入有关的隐含对象: param, paramValues --> score: ${param.score } <%-- <%= request.getParameter("score") %> --%> <br> names: ${paramValues.name[0].class.name } <%-- <%= request.getParameterValues("name")[0].getClass().getName() %> --%>
<!-- 6. 其他隐含对象: pageContext 等(cookie, header, initParam 只需了解.) --> pageContext: pageContext 即为 PageContext 类型, 但只能读取属性就可以一直的 . 下去。 <br> contextPath: ${pageContext.request.contextPath } <br> sessionId: ${pageContext.session.id } <br> sessionAttributeNames: ${pageContext.session.attributeNames } <br> initParam: ${initParam.initName } <br> Accept-Language: ${header["Accept-Language"] } <br> JSESSIONID: ${cookie.JSESSIONID.name } -- ${cookie.JSESSIONID.value } <br>
<!-- 7. EL 的运算符 --> ${param.score > 60 ? "及格" : "不及格" } <br> <% List<String> names = new ArrayList<String>(); names.add("abc"); request.setAttribute("names", names); %> <!-- empty 可以作用于一个集合, 若该集合不存在或集合中没有元素, 其结果都为 true --> names is empty: ${empty requestScope.names }
页面中不出现任何Java代码
使用标签
index.jsp
<%@page import="com.atguigu.javaweb.Customer"%> <%@page import="java.util.ArrayList"%> <%@page import="java.util.List"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!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> <% //模拟 Servlet 中的操作. List<Customer> customers = new ArrayList<Customer>(); customers.add(new Customer(1, "AA", 12)); customers.add(new Customer(2, "BB", 13)); customers.add(new Customer(3, "CC", 14)); customers.add(new Customer(4, "DD", 15)); customers.add(new Customer(5, "EE", 16)); request.setAttribute("customers", customers); %> <jsp:forward page="testtag.jsp"></jsp:forward> </body> </html>
testtag.jsp
<%@page import="com.atguigu.javaweb.Customer"%> <%@page import="java.util.List"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!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> <!-- 在页面上对 request 中的 customers 属性进行遍历, 打印 id, name, age --> <c:forEach items="${requestScope.customers }" var="customer"> --${customer.id }, ${customer.name }, ${customer.age }<br> </c:forEach> <%-- List<Customer> customers = (List<Customer>)request.getAttribute("customers"); if(customers != null){ for(Customer customer: customers){ %> <%= customer.getId() %>, <%= customer.getName() %>, <%= customer.getAge() %><br> <% } } --%> </body> </html>
二、自定义标签
HelloWorld
①. 创建一个标签处理器类: 实现 SimpleTag 接口.
package com.atguigu.javaweb.tag; import java.io.IOException; import javax.servlet.jsp.JspContext; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.JspFragment; import javax.servlet.jsp.tagext.JspTag; import javax.servlet.jsp.tagext.SimpleTag; public class HelloSimpleTag implements SimpleTag { @Override public void doTag() throws JspException, IOException { System.out.println("doTag"); } @Override public JspTag getParent() { System.out.println("getParent"); return null; } @Override public void setJspBody(JspFragment arg0) { System.out.println("setJspBody"); } @Override public void setJspContext(JspContext arg0) { System.out.println("setJspContext"); } @Override public void setParent(JspTag arg0) { System.out.println("setParent"); } }
②. 在 WEB-INF 文件夹下新建一个 .tld(标签库描述文件) 为扩展名的 xml 文件. 并拷入固定的部分: 并对
description, display-name, tlib-version, short-name, uri 做出修改
<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>JSTL 1.1 core library</description> <display-name>JSTL core</display-name> <tlib-version>1.1</tlib-version> <short-name>c</short-name> <uri>http://java.sun.com/jsp/jstl/core</uri> </taglib>
③. 在 tld 文件中描述自定义的标签:
<!-- 描述自定义的 HelloSimpleTag 标签 --> <tag> <!-- 标签的名字: 在 JSP 页面上使用标签时的名字 --> <name>hello</name> <!-- 标签所在的全类名 --> <tag-class>com.atguigu.javaweb.tag.HelloSimpleTag</tag-class> <!-- 标签体的类型 --> <body-content>empty</body-content> </tag>
④. 在 JSP 页面上使用自定义标签:
> 使用 taglib 指令导入标签库描述文件: <%@taglib uri="http://www.atguigu.com/mytag/core" prefix="atguigu" %>
> 使用自定义的标签: <atguigu:hello/>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!-- 导入标签库(描述文件) --> <%@taglib uri="http://www.atguigu.com/mytag/core" prefix="atguigu" %> <!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> <atguigu:hello /> </body> </html>
使用自定义标签的JSP和tld 文件的对应:
带属性的自定义标签
上面的例子太简单了,下面使用带属性的自定义标签
标签有value和count两个属性,我们想实现打印value值count次,即打印我们传入的参数10次
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!-- 导入标签库(描述文件) --> <%@taglib uri="http://www.atguigu.com/mytag/core" prefix="atguigu" %> <!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> <atguigu:hello value="${param.name }" count="10"/> </body> </html>
属性需要在tld文件中进行设置
value是必需的属性,count不能用表达式
<?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"> <!-- 描述 TLD 文件 --> <description>MyTag 1.0 core library</description> <display-name>MyTag core</display-name> <tlib-version>1.0</tlib-version> <!-- 建议在 JSP 页面上使用的标签的前缀 --> <short-name>atguigu</short-name> <!-- 作为 tld 文件的 id, 用来唯一标识当前的 TLD 文件, 多个 tld 文件的 URI 不能重复. 通过 JSP 页面的 taglib 标签的 uri 属性来引用. --> <uri>http://www.atguigu.com/mytag/core</uri> <!-- 描述自定义的 HelloSimpleTag 标签 --> <tag> <!-- 标签的名字: 在 JSP 页面上使用标签时的名字 --> <name>hello</name> <!-- 标签所在的全类名 --> <tag-class>com.atguigu.javaweb.tag.HelloSimpleTag</tag-class> <!-- 标签体的类型 --> <body-content>empty</body-content> <!-- 描述当前标签的属性 --> <attribute> <!-- 属性名 --> <name>value</name> <!-- 该属性是否被必须 --> <required>true</required> <!-- rtexprvalue: runtime expression value 当前属性是否可以接受运行时表达式的动态值 --> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>count</name> <required>false</required> <rtexprvalue>false</rtexprvalue> </attribute> </tag> </taglib>
标签处理器类
package com.atguigu.javaweb.tag; import java.io.IOException; import javax.servlet.jsp.JspContext; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.JspFragment; import javax.servlet.jsp.tagext.JspTag; import javax.servlet.jsp.tagext.SimpleTag; public class HelloSimpleTag implements SimpleTag { private String value; private String count; public void setValue(String value) { this.value = value; } public void setCount(String count) { this.count = count; } //标签体逻辑实际应该编写到该方法中. @Override public void doTag() throws JspException, IOException { JspWriter out = pageContext.getOut(); int c = 0; c = Integer.parseInt(count); for(int i = 0; i < c; i++){ out.print((i + 1) + ": " + value); out.print("<br>"); } } @Override public JspTag getParent() { System.out.println("getParent"); return null; } @Override public void setJspBody(JspFragment arg0) { System.out.println("setJspBody"); } private PageContext pageContext; //JSP 引擎调用, 把代表 JSP 页面的 PageContext 对象传入 //PageContext 可以获取 JSP 页面的其他 8 个隐含对象. //所以凡是 JSP 页面可以做的标签处理器都可以完成. @Override public void setJspContext(JspContext arg0) { System.out.println(arg0 instanceof PageContext); this.pageContext = (PageContext) arg0; } @Override public void setParent(JspTag arg0) { System.out.println("setParent"); } }
小结:
setJspContext: 一定会被 JSP 引擎所调用, 先于 doTag, 把代表 JSP 引擎的 pageContext 传给标签处理器类.
@Override public void setJspContext(JspContext arg0) { System.out.println(arg0 instanceof PageContext); this.pageContext = (PageContext) arg0; }
小结
①. 先在标签处理器类中定义 setter 方法. 建议把所有的属性类型都设置为 String 类型.
private String value; private String count; public void setValue(String value) { this.value = value; } public void setCount(String count) { this.count = count; }
②. 在 tld 描述文件中来描述属性:
<!-- 描述当前标签的属性 --> <attribute> <!-- 属性名, 需和标签处理器类的 setter 方法定义的属性相同 --> <name>value</name> <!-- 该属性是否被必须 --> <required>true</required> <!-- rtexprvalue: runtime expression value 当前属性是否可以接受运行时表达式的动态值 --> <rtexprvalue>true</rtexprvalue> </attribute>
③. 在页面中使用属性, 属性名同 tld 文件中定义的名字.
<atguigu:hello value="${param.name }" count="10"/>
练习
定制一个带有两个属性的标签<max>, 用于计算并输出两个数的最大值
实现SimpleTag接口会有大量的空方法,通常情况下开发简单标签直接继承 SimpleTagSupport 就可以了。可以直接调用其对应的 getter 方法得到对应的 API
public class SimpleTagSupport implements SimpleTag{ public void doTag() throws JspException, IOException{} private JspTag parentTag; public void setParent( JspTag parent ) { this.parentTag = parent; } public JspTag getParent() { return this.parentTag; } private JspContext jspContext; public void setJspContext( JspContext pc ) { this.jspContext = pc; } protected JspContext getJspContext() { return this.jspContext; } private JspFragment jspBody; public void setJspBody( JspFragment jspBody ) { this.jspBody = jspBody; } protected JspFragment getJspBody() { return this.jspBody; } }
带标签体的自定义标签
JspFragment
该类的实例对象代表 JSP 页面中的一段符合 JSP 语法规范的 JSP 片段,这段 JSP 片段不能包含 JSP 脚本元素(<% … %>)
JSP 引擎在处理简单标签的标签体时,会把标签体内容用一个 JspFragment 对象表示,并调用标签处理器对象的 setJspBody 方法把 JspFragment 对象传递给标签处理器对象。得到代表标签体的 JspFragment 对象后,标签开发者和就可以在标签处理器中根据需要调用 JspFragment 对象的方法,进而决定如何处理标签体。
getJspContext 方法:该方法用于返回代表调用页面的 JspContext 对象
invoke 方法(java.io.Writer out):该方法用于执行 JspFragment 对象所代表的 JSP 代码片段。在 doTag() 方法中可以根据需要调用该方法。
- 该方法的参数 out 用于指定将 JspFragment 对象的执行结果写入到哪个输出流对象中。若传递参数 out 的值为 null,则将执行结果写入到 JspContext.geOut() 方法返回的输出流对象中。
- 若想在标签处理器中修改标签体内容:需在调用 invoke 方法时指定一个可取出结果数据的输出流对象(如:StringWriter),让标签体的执行结果输出到该输出流中,然后从该输出流对象中取出数据进行修改后再输出到目标设备
示例
1)有标签体的标签
<atguigu:testJspFragment>abcdefg</atguigu:testJspFragment>
test.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="aidata" uri="http://www.aidata.com/mytag/core" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <aidata:testJspFragment>HelloWorld</aidata:testJspFragment> </body> </html>
2)在自定义标签的标签处理器中使用 JspFragment 对象封装标签体信息
TestJspFragment
package com.aidata.web; import java.io.IOException; import java.io.StringWriter; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.JspFragment; import javax.servlet.jsp.tagext.SimpleTagSupport; public class TestJspFragment extends SimpleTagSupport { @Override public void doTag() throws JspException, IOException { JspFragment bodyContent = getJspBody(); // JspFragment.invoke(Writer); // Writer即位标签体内输出的字符流,若为null // 则输出getJspContext().getOut(),即输出到页面 // bodyContent.invoke(null); // 为了打印的到控制台,用stringwriter // 1.用StringWriter得到标签体的内容 StringWriter sw = new StringWriter(); bodyContent.invoke(sw); // 2.把标签体的内容都变为大写 String content = sw.toString().toUpperCase(); // 3.获取JSP页面的out隐含对象,输出到页面上 getJspContext().getOut().print(content); System.out.println(sw.toString()); } }
若配置了标签含有标签体, 则 JSP 引擎会调用 setJspBody() 方法把 JspFragment 传递给标签处理器类
在 SimpleTagSupport 中还定义了一个 getJspBody() 方法, 用于返回 JspFragment 对象.JspFragment 的 invoke(Writer) 方法: 把标签体内容从 Writer 中输出, 若为 null,则等同于 invoke(getJspContext().getOut()), 即直接把标签体内容输出到页面上
有时, 可以 借助于 StringWriter, 可以在标签处理器类中先得到标签体的内容,即上面代码中的:
//1. 利用 StringWriter 得到标签体的内容. StringWriter sw = new StringWriter(); bodyContent.invoke(sw); //2. 把标签体的内容都变为大写 String content = sw.toString().toUpperCase();
3)配置tld文件
mytag.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"> <!-- 描述 TLD 文件 --> <description>MyTag 1.2 core library</description> <display-name>MyTag core</display-name> <tlib-version>1.0</tlib-version> <!-- 建议在 JSP 页面上使用的标签的前缀 --> <short-name>aidata</short-name> <!-- 作为 tld 文件的 id, 用来唯一标识当前的 TLD 文件, 多个 tld 文件的 URI 不能重复. 通过 JSP 页面的 taglib 标签的 uri 属性来引用. --> <uri>http://www.aidata.com/mytag/core</uri> <!-- 描述自定义的 HelloSimpleTag 标签 --> <tag> <!-- 标签的名字: 在 JSP 页面上使用标签时的名字 --> <name>testJspFragment</name> <!-- 标签所在的全类名 --> <tag-class>com.aidata.web.TestJspFragment</tag-class> <!-- 标签体的类型 --> <body-content>scriptless</body-content> </tag> </taglib>
在 tld 文件中, 使用 body-content 节点来描述标签体的类型:
<body-content>: 指定标签体的类型, 大部分情况下, 取值为 scriptless。可能取值有 3 种:
- empty: 没有标签体
- scriptless: 标签体可以包含 el 表达式和 JSP 动作元素,但不能包含 JSP 的脚本元素
- tagdependent: 表示标签体交由标签本身去解析处理。
若指定 tagdependent,在标签体中的所有代码都会原封不动的交给标签处理器,而不是将执行结果传递给标签处理器
<body-content>tagdependent</body-content>
练习
定义一个自定义标签: <aidata:printUpper time="10">abcdefg</atguigu> 把标签体内容转换为大写,并输出 time 次到
浏览器上
标签处理器类
package com.aidata.web; import java.io.IOException; import java.io.StringWriter; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.JspFragment; import javax.servlet.jsp.tagext.SimpleTagSupport; public class PrintUpperTag extends SimpleTagSupport { private String time; public void setTime(String time) { this.time = time; } @Override public void doTag() throws JspException, IOException { // 1.得到标签体内容 JspFragment bodyContent = getJspBody(); StringWriter sw = new StringWriter(); bodyContent.invoke(sw); String content = sw.toString(); // 2.变为大写 content = content.toUpperCase(); // 3.得到out隐含变量 // 4.循环输出 int count = 1; try { count = Integer.parseInt(time); } catch (Exception e) { } for (int i = 0; i < count; i++) { getJspContext().getOut().print(i + 1 + "." + content + "<br>"); } } }
配置tld
<tag> <!-- 标签的名字: 在 JSP 页面上使用标签时的名字 --> <name>printUpper</name> <!-- 标签所在的全类名 --> <tag-class>com.aidata.web.PrintUpperTag</tag-class> <!-- 标签体的类型 --> <body-content>scriptless</body-content> <attribute> <name>time</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag>
test.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="aidata" uri="http://www.aidata.com/mytag/core" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <aidata:printUpper time="10">abcdefg</aidata:printUpper> </body> </html>
实现 forEach 标签
首先使用JSTL的forEach标签
定义Java bean Customer
package com.aidata.web; public class Customer { private Integer id; private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Customer() { } public Customer(Integer id, String name) { super(); this.id = id; this.name = name; } }
test.jsp
<%@page import="com.aidata.web.Customer"%> <%@page import="java.util.ArrayList"%> <%@page import="java.util.List"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <% List<Customer> customers = new ArrayList<Customer>(); customers.add(new Customer(1, "aaa")); customers.add(new Customer(2, "bbb")); customers.add(new Customer(3, "ccc")); customers.add(new Customer(4, "ddd")); customers.add(new Customer(5, "eee")); request.setAttribute("customers", customers); %> <c:forEach items="${requestScope.customers }" var="cust"> ${cust.id } -- ${cust.name } <br> </c:forEach> </body> </html>
自定义forEach
处理器类
> 两个属性: items(集合类型, Collection), var(String 类型)
> doTag:
- 遍历 items 对应的集合
- 把正在遍历的对象放入到 pageContext 中, 键: var, 值: 正在遍历的对象.
- 把标签体的内容直接输出到页面上.
package com.aidata.web; import java.io.IOException; import java.util.Collection; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.SimpleTagSupport; public class ForEachTag extends SimpleTagSupport { private Collection<?> items; public void setItems(Collection<?> items) { this.items = items; } private String var; public void setVar(String var) { this.var = var; } @Override public void doTag() throws JspException, IOException { // 遍历items对应的集合 if (items != null) { for (Object obj : items) { // 把正在遍历的对象放入到pageContext中,键:var,值:正在遍历的对象 getJspContext().setAttribute(var, obj); // 把标签体的内容直接输出到页面 getJspBody().invoke(null); } } } }
tld配置文件
<tag> <!-- 标签的名字: 在 JSP 页面上使用标签时的名字 --> <name>forEach</name> <!-- 标签所在的全类名 --> <tag-class>com.aidata.web.ForEachTag</tag-class> <!-- 标签体的类型 --> <body-content>scriptless</body-content> <attribute> <name>items</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>var</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag>
jsp
<!--<c:forEach items="${requestScope.customers }" var="cust"> ${cust.id } -- ${cust.name } <br> </c:forEach>--> <aidata:forEach items="${requestScope.customers }" var="cust"> ${cust.id } -- ${cust.name } <br> </aidata:forEach>
带父标签的自定义标签