JavaWeb(七):EL表达式

语法

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>

带父标签的自定义标签

猜你喜欢

转载自www.cnblogs.com/aidata/p/12005273.html