zoukankan      html  css  js  c++  java
  • JavaWeb(七):EL表达式、自定义标签和JSTL

     一、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>

    二、自定义标签

    2.1 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 文件的对应:

    2.2 带属性的自定义标签

    上面的例子太简单了,下面使用带属性的自定义标签

    标签有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;
        }   
    }

    2.3 带标签体的自定义标签

    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>

    2.4 带父标签的自定义标签

    1). 父标签无法获取子标签的引用, 父标签仅把子标签作为标签体来使用.

    test.jsp

        <!-- 父标签打印name到控制台 -->
        <aidata:parentTag>
            <!-- 子标签以父标签的标签体存在,希望子标签把父标签的name属性打印到JSP页面上 -->
            <aidata:sonTag/>
        </aidata:parentTag>

    ParentTag

    package com.aidata.web;
    
    import java.io.IOException;
    
    import javax.servlet.jsp.JspException;
    import javax.servlet.jsp.tagext.SimpleTagSupport;
    
    public class ParentTag extends SimpleTagSupport {
    
        private String name = "www.aidata.com";
    
        public String getName() {
            return name;
        }
    
        @Override
        public void doTag() throws JspException, IOException {
            System.out.println("父标签处理器类的name" + name);
            getJspBody().invoke(null);
        }
    }

    2). 子标签可以通过 getParent() 方法来获取父标签的引用(需继承 SimpleTagSupport 或自实现 SimpleTag 接口的该方法):
    若子标签的确有父标签, JSP 引擎会把代表父标签的引用通过 setParent(JspTag parent) 赋给标签处理器

    3). 注意: 父标签的类型是 JspTag 类型. 该接口是一个空接口, 但是来统一 SimpleTag 和 Tag 的. 实际使用需要进行类型的强制转换.

     SonTag

    package com.aidata.web;
    
    import java.io.IOException;
    
    import javax.servlet.jsp.JspException;
    import javax.servlet.jsp.tagext.JspTag;
    import javax.servlet.jsp.tagext.SimpleTagSupport;
    
    public class SonTag extends SimpleTagSupport {
    
        @Override
        public void doTag() throws JspException, IOException {
            // 1. 得到父标签的引用
            JspTag parent = getParent();
    
            // 2. 获取父标签的 name 属性
            ParentTag parentTag = (ParentTag) parent;
            String name = parentTag.getName();
    
            // 3. 把 name 值打印到 JSP 页面上.
            getJspContext().getOut().print("子标签输出name: " + name);
        }
    
    }

    4). 在 tld 配置文件中,无需为父标签有额外的配置。但子标签是是以标签体的形式存在的, 所以父标签的 <body-content></body-content>需设置为 scriptless

        <tag>
            <!-- 标签的名字: 在 JSP 页面上使用标签时的名字 -->
            <name>parentTag</name>
    
            <!-- 标签所在的全类名 -->
            <tag-class>com.aidata.web.ParentTag</tag-class>
            <!-- 标签体的类型 -->
            <body-content>scriptless</body-content>
        </tag>
        <tag>
            <!-- 标签的名字: 在 JSP 页面上使用标签时的名字 -->
            <name>sonTag</name>
    
            <!-- 标签所在的全类名 -->
            <tag-class>com.aidata.web.SonTag</tag-class>
            <!-- 标签体的类型 -->
            <body-content>empty</body-content>
        </tag>

    实现choose when otherwise标签

    <c:choose>
        <c:when test="${param.age > 24}">大学毕业</c:when>
        <c:when test="${param.age > 20}">高中毕业</c:when>
        <c:otherwise>高中以下...</c:otherwise>
    </c:choose>

    > 开发 3 个标签:choose,when,otherwise
    > 其中 when 标签有一个 boolean 类型的属性: test
    > choose 是 when 和 otherwise 的父标签
    > when 在 otherwise 之前使用
    > 在父标签 choose 中定义一个 "全局" 的 boolean 类型的 flag:用于监控when是否执行。判断子标签在满足条件的情况下是否执行.

    • 若 when 的 test 为 true,即满足条件,且 when 的父标签的 flag 也为 true,则执行 when 的标签体(正常输出标签体的内容)
    • 同时把 flag 设置为 false
    • 若 when 的 test 为 true,且 when 的父标签的 flag 为 false, 则不执行标签体.
    • 若flag 为 true, otherwise 执行标签体.

    父标签

    ChooseTag

    package com.aidata.web;
    
    import java.io.IOException;
    
    import javax.servlet.jsp.JspException;
    import javax.servlet.jsp.tagext.SimpleTagSupport;
    
    public class ChooseTag extends SimpleTagSupport {
        
        private boolean flag = true;
        
        public void setFlag(boolean flag) {
            this.flag = flag;
        }
        
        public boolean isFlag() {
            return flag;
        }
        
        @Override
        public void doTag() throws JspException, IOException {
            getJspBody().invoke(null);
        }
    }

    子标签

    WhenTag

    package com.aidata.web;
    
    import java.io.IOException;
    
    import javax.servlet.jsp.JspException;
    import javax.servlet.jsp.tagext.SimpleTagSupport;
    
    public class WhenTag extends SimpleTagSupport{
    
        private boolean test;
        
        public void setTest(boolean test) {
            this.test = test;
        }
        
        @Override
        public void doTag() throws JspException, IOException {
            if(test){
                
                ChooseTag chooseTag = (ChooseTag) getParent();
                boolean flag = chooseTag.isFlag();
                
                if(flag){
                    getJspBody().invoke(null);
                    chooseTag.setFlag(false);
                }
                
            }
        }
        
    }

    OtherwiseTag

    package com.aidata.web;
    
    import java.io.IOException;
    
    import javax.servlet.jsp.JspException;
    import javax.servlet.jsp.tagext.SimpleTagSupport;
    
    public class OtherwiseTag extends SimpleTagSupport{
    
        @Override
        public void doTag() throws JspException, IOException {
            ChooseTag chooseTag = (ChooseTag) getParent();
            
            if(chooseTag.isFlag()){
                getJspBody().invoke(null);
            }
        }
        
    }

     jsp

        <aidata:choose>
            <aidata:when test="${param.age > 24}">^大学毕业</aidata:when>
            <aidata:when test="${param.age > 20}">^高中毕业</aidata:when>
            <aidata:otherwise>^高中以下...</aidata:otherwise>
        </aidata:choose>

    tld

        <tag>
            <name>choose</name>
            <tag-class>com.aidata.web.ChooseTag</tag-class>
            <body-content>scriptless</body-content>
        </tag>
        
        <tag>
            <name>when</name>
            <tag-class>com.aidata.web.WhenTag</tag-class>
            <body-content>scriptless</body-content>
            
            <attribute>
                <name>test</name>
                <required>true</required>
                <rtexprvalue>true</rtexprvalue>
            </attribute>
        </tag>
        
        <tag>
            <name>otherwise</name>
            <tag-class>com.aidata.web.OtherwiseTag</tag-class>
            <body-content>scriptless</body-content>
        </tag>

    EL自定义函数

    JSTL提供了一些EL自定义函数

    引入

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

    使用

        <!-- 使用一个 EL 的自定义函数 -->
        ${fn:length(param.name) } 
        <br><br>
        
        ${fn:toUpperCase(param.name1) }

    自定义EL函数

    步骤

    • 编写 EL 自定义函数映射的Java 类中的静态方法,这个 Java 类必须带有 public 修饰符,方法必须是这个类的带有 public 修饰符的静态方法
      • package com.aidata.web;
        
        public class MyELFunction {
        
            public static String concat(String str1, String str2) {
        
                return str1 + str2;
            }
        }
    • 编写标签库描述文件(tld 文件), 在 tld 文件中描述自定义函数
      •     <!-- 描述 EL 的自定义函数 -->
            <function>    
                <name>concat</name>
                <function-class>com.atguigu.javaweb.MyELFunction</function-class>
                <function-signature>java.lang.String concat(java.lang.String, java.lang.String)</function-signature>
            </function>
    • 在 JSP 页面中导入和使用自定义函数
    •     <!-- 测试自定义的 EL 函数 -->
          ${aidata:concat(param.name1, param.name2)}

    三、JSTL

    JSTL 全名为JavaServer Pages Standard Tag Library,是由JCP(Java Community Process)所指定的标准规格,它主要提供给Java Web 开发人员一个标准通用的标签函数库。Web 程序开发人员能够利用JSTL 和EL来开发Web 程序,取代传统直接在页面上嵌入Java程序(Scripting)的做法,以提高程序可读性、维护性和方便性。

    最重要的是核心标签库

    使用前引入jstl.jar和standard.jar即可

    核心标签库(Core)主要有:基本输入输出、流程控制、迭代操作和URL操作。

    3.1  表达式操作

    <c:out>

    <c:out>主要用来显示数据的内容,就像是 <%= scripting-language %> 一样

    语法

     属性

     假若 value为null,会显示default 的值;假若没有设定default的值,则会显示一个空的字符串。

    一般来说,<c:out>默认会将 <、>、’、” 和 & 转换为 &lt;、&gt;、&#039;、&#034; 和 &amp;。假若不想转换时,只需要设定<c:out>的escapeXml 属性为fasle 就可以了

    EL表达式遇到特殊字符如下面的<,无法输出

    out则可以自动的转换

        <h4>c:out: 可以对特殊字符进行转换. </h4>
        
        <% 
            request.setAttribute("book", "<<Java>>");
        %>
        book: ${requestScope.book }
        <br><br>
        book: <c:out value="${requestScope.book }" default="booktitle"></c:out>

    <c:set>

    <c:set>主要用来将变量储存至JSP范围中或是JavaBean 的属性

    语法

                              语法3:

    使用<c:set>时,var 主要用来存放表达式的结果;scope 则是用来设定储存的范围,例如:假若scope="session",则将会把数据储存在session中。如果<c:set>中没有指定scope时,则它会默认存在Page 范围里。

        <h4>c:set: 可以为域赋属性值, 其中 value 属性支持 EL 表达式; 还可以为域对象中的 JavaBean 的属性赋值, target, value都支持 EL 表达式</h4>
        
        <c:set var="name" value="ATGUIGU" scope="page"></c:set>
        <%-- 
            pageContext.setAttribute("name", "atguigu");
        --%>
        name: ${pageScope.name }    
        
        <br><br>
        <c:set var="subject" value="${param.subject }" scope="session"></c:set>
        subject: ${sessionScope.subject }
        
        <br><br>
        <% 
            Customer cust = new Customer();
            cust.setId(1001);
            request.setAttribute("cust", cust);
        %>
        ID: ${requestScope.cust.id }
    <!-- 为javabean属性赋值 -->
    <c:set target="${requestScope.cust }" property="id" value="${param.id }"></c:set> <br> ID: ${requestScope.cust.id }

    <c:remove>

    <c:remove>主要用来移除变量。

    语法

    <c:remove var="varName" [scope="{ page|request|session|application }"] />

    属性

    <c:remove>必须要有var属性,即要被移除的属性名称,scope 则可有可无,例如:

    <c:remove var="number" scope="session" />

    将number 变量从Session 范围中移除。若我们不设定scope,则<c:remove>将会从Page、Request、Session 及Application 中顺序寻找是否存在名称为number 的数据,若能找到时,则将它移除掉,反之则不会做任何的事情。

        <h4>c:remove: 移除指定域对象的指定属性值</h4>
        <c:set value="1997-09-1" var="date" scope="session"></c:set>
        date: ${sessionScope.date }
        <br><br>
    
        <c:remove var="date" scope="session"/>
        date: --${sessionScope.date }--

    3.2 流程控制

    流程控制分类中包含四个标签:<c:if>、<c:choose>、<c:when>和<c:otherwise>

    <c:if>
    <c:if>的用途就和我们一般在程序中用的if 一样。

    语法

     属性

     <c:if> 标签必须要有test 属性,当test 中的表达式结果为true 时,则会执行本体内容;如果为false,则不会执行。例如:${param.username = = 'admin'},如果param.username 等于admin时,结果为true;若它的内容不等于admin时,则为false。

        <h4>c:if: 不能实现 else 操作, 但可以把结果储存起来。 </h4>
        <c:if test="${requestScope.age > 18 }">成年了!</c:if>
        <br><br>
        
        <c:if test="${param.age > 18 }" var="isAdult" scope="request"></c:if>
        isAdult: <c:out value="${requestScope.isAdult }"></c:out>

    <c:choose>
    <c:choose>本身只当做 <c:when> 和 <c:otherwise> 的父标签。

    语法

    <c:choose>的本体内容只能有:

    • ·空白
    • ·1 或多个 <c:when>
    • ·0 或多个 <c:otherwise>

    若使用<c:when>和<c:otherwise>来做流程控制时,两者都必须为<c:choose>的子标

    <c:when>
    <c:when> 的用途就和我们一般在程序中用的when 一样。

    语法

     属性

     <c:when>必须在<c:choose>和</c:choose>之间,在同一个<c:choose>中时,<c:when>必须在<c:otherwise>之前。<c:when>必须有test 属性,当test 中的表达式结果为true 时,则会执行本体内容;如果为false 时,则不会执行。

    <c:otherwise>
    在同一个 <c:choose> 中,当所有 <c:when> 的条件都没有成立时,则执行<c:otherwise> 的本体内容。

    语法

    <c:otherwise> 必须在 <c:choose> 和 </c:choose>之间,在同一个 <c:choose> 中时,<c:otherwise> 必须为最后一个标签。在同一个<c:choose> 中,假若所有<c:when> 的test 属性都不为true 时,则执行<c:otherwise> 的本体内容。

    <h4>
            c:choose, c:when, c:otherwise: 可以实现 if...else if...else if...else 的效果. 但较为麻烦
            其中: c:choose 以 c:when, c:otherwise 的父标签出现.
            c:when, c:otherwise 不能脱离 c:choose 单独使用.
            c:otherwise 必须在 c:when 之后使用。 
        </h4>
        <c:choose>        
            <c:when test="${param.age > 60 }">
                老年
            </c:when>
            <c:when test="${param.age > 35 }">
                中年
            </c:when>
            <c:when test="${param.age > 18 }">
                青年
            </c:when>
            <c:otherwise>
                未成年. 
            </c:otherwise>
        </c:choose>
    
        <c:set value="20" var="age" scope="request"></c:set>

    3.3 迭代操作

    <c:forEach>
    <c:forEach> 为循环控制,它可以将集合(Collection)中的成员循序浏览一遍。运作方式为当条件符合时,就会持续重复执行<c:forEach>的本体内容。

    语法

    属性

    假若有begin 属性时,begin 必须大于等于 0

    • ·假若有end 属性时,必须大于begin
    • ·假若有step 属性时,step 必须大于等于0

    Null 和错误处理

    • ·假若items 为null时,则表示为一空的集合对象
    • ·假若begin 大于或等于items 时,则迭代不运算

    如果要循序浏览一个集合对象,并将它的内容显示出来,就必须有items 属性。

    <!-- 遍历 Collection, 遍历数组同 Collection -->
        <c:forEach items="${requestScope.custs }" var="cust"
            varStatus="status">
            ${status.index}, ${status.count}, ${status.first}, ${status.last}: ${cust.id }: ${cust.name }<br>
        </c:forEach>
        
        <!-- 遍历 Map -->
        <% 
            Map<String, Customer> custMap = new HashMap<String, Customer>();
            custMap.put("a", new Customer(1, "AAA")); //index: 0 
            custMap.put("b", new Customer(2, "BBB")); //index: 0 
            custMap.put("c", new Customer(3, "CCC")); //index: 0 
            custMap.put("d", new Customer(4, "DDD")); //index: 0 
            custMap.put("e", new Customer(5, "EEE")); //index: 0 
            custMap.put("f", new Customer(6, "FFF")); //index: 0 
            
            request.setAttribute("custMap", custMap);
        %>
        
        <br><br>
        <c:forEach items="${requestScope.custMap }" var="cust">
            ${cust.key } - ${cust.value.id } - ${cust.value.name }<br>
        </c:forEach>
        
        <% 
            String [] names = new String[]{"A", "B", "C"};
            request.setAttribute("names", names);
        %>
        <br><br>
        <c:forEach var="name" items="${names }">${name }-</c:forEach>
        
        <br><br>
        <c:forEach items="${pageContext.session.attributeNames }" var="attrName">
            ${attrName }-
        </c:forEach>
       <h4>c:forTokens: 处理字符串的, 类似于 String 的 split() 方法</h4>
        <c:set value="a,b,c.d.e.f;g;h;j" var="test" scope="request"></c:set>
        <c:forTokens items="${requestScope.test }" delims="." var="s">
            ${s }<br>
        </c:forTokens>

    3.4 URL操作

    JSTL 包含三个与URL 操作有关的标签,它们分别为:<c:import>、<c:redirect>和<c:url>。它们主要的功能是:用来将其他文件的内容包含起来、网页的导向,还有url 的产生。

    <c:url>
    <c:url>主要用来产生一个URL。

    语法

    属性

        <h4>
            c:url 产生一个 url 地址. 可以 Cookie 是否可用来智能进行 URL 重写, 对 GET 请求的参数进行编码
            可以把产生的 URL 存储在域对象的属性中.
            还可以使用 c:param 为 URL 添加参数. c:url 会对参数进行自动的转码. 
            value 中的 / 代表的是当前 WEB 应用的根目录. 
        </h4>
        <c:url value="/test.jsp" var="testurl" scope="page">
            <c:param name="name" value="尚硅谷"></c:param>
        </c:url>
        
        url: ${testurl }
    
        <h4>
            c:redirect 使当前 JSP 页面重定向到指定的页面. 使当前 JSP 转发到指定页面可以使用
            <%--  
            <jsp:forward page="/test.jsp"></jsp:forward>    
            --%>
            / 代表的是当前 WEB 应用的根目录. 
            
            response.sendRedirect("/test.jsp") / 代表 WEB 站点的根目录
        </h4>
        <%-- 
        <c:redirect url="http://www.atguigu.com"></c:redirect>
        <c:redirect url="/test.jsp"></c:redirect>
        --%>
        
        <h4>c:import 可以包含任何页面到当前页面</h4>
        <c:import url="http://www.baidu.com"></c:import>

      

  • 相关阅读:
    pythonon ddt数据驱动二(json, yaml 驱动)
    selenium 使用隐藏模式打开浏览器
    Selenium -Java (WebDriver)总结(一)---启动浏览器、设置profile&加载插件
    python自动化测试 excle数据驱动
    Selenium+Maven+Jenkins+testNg自动生成测试报告
    【转】java编程思想第20章的注解例子用到的com.sun.mirror的jar包
    [转]java注解与APT技术
    【转】Android官方架构项目之MVP + Clean
    [转]彻底明确怎样设置minSdkVersion和targetSdkVersion
    [转]Android专家级别的面试总结
  • 原文地址:https://www.cnblogs.com/aidata/p/12005273.html
Copyright © 2011-2022 走看看