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"%>




Insert title here


    
    
username: value="<%= request.getParameter("username") == null ? "" : request.getParameter("username")%>"/> username: value="${param.username }"/>
username: <%= request.getParameter("username") %>

class="com.atguigu.javaweb.Customer" scope="session"> age: <% Customer customer2 = (Customer)session.getAttribute("customer"); out.print(customer2.getAge()); %>
age:

<% application.setAttribute("time", new Date()); %> To El2 Page

 

下面都在el2.jsp中

可以使用点和中括号运算符

    
    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);
    %>
    
    
name: ${sessionScope["com.atguigu.customer"].name }

 

EL中的隐含对象,EL可以大大简化代码

    
    <% 
        Customer cust2 = new Customer();
        cust2.setAge(28);
        request.setAttribute("customer", cust2);
    %>
    
    age: ${customer.age } 

 

可以自动类型转换

上面的结果是加了11的数

下面的结果是字符串

    
    score: ${param.score + 11}
    
score: <%= request.getParameter("score") + 11 %>

 

    
    time: ${applicationScope.time.time }
    <%-- 
    <%= application.getAttribute("time") %>
    --%>

 

 

    
    score: ${param.score }
    <%-- 
    <%= request.getParameter("score") %>
    --%>
    
names: ${paramValues.name[0].class.name } <%-- <%= request.getParameterValues("name")[0].getClass().getName() %> --%>

 

 

    
    pageContext: pageContext 即为 PageContext 类型, 但只能读取属性就可以一直的 . 下去。 
    
contextPath: ${pageContext.request.contextPath }
sessionId: ${pageContext.session.id }
sessionAttributeNames: ${pageContext.session.attributeNames }
initParam: ${initParam.initName }
Accept-Language: ${header["Accept-Language"] }
JSESSIONID: ${cookie.JSESSIONID.name } -- ${cookie.JSESSIONID.value }

 

 

    
    ${param.score > 60 ? "及格" : "不及格" }
    
<% List names = new ArrayList(); names.add("abc"); request.setAttribute("names", names); %> 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"%>




Insert title here


    
    <% 
        //模拟 Servlet 中的操作.
        List customers = new ArrayList();
        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);
    %>
    
    
    

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" %>    
    




Insert title here



    
    
    
    
        --${customer.id }, ${customer.name }, ${customer.age }
<%-- List customers = (List)request.getAttribute("customers"); if(customers != null){ for(Customer customer: customers){ %> <%= customer.getId() %>, <%= customer.getName() %>, <%= customer.getAge() %>
<% } } --%>

 

 

二、自定义标签

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 librarydescription>
  <display-name>JSTL coredisplay-name>
  <tlib-version>1.1tlib-version>
  <short-name>cshort-name>
  <uri>http://java.sun.com/jsp/jstl/coreuri>
  
taglib>

③. 在 tld 文件中描述自定义的标签:


  <tag>
      
      <name>helloname>
      
      
      <tag-class>com.atguigu.javaweb.tag.HelloSimpleTagtag-class>
      
      <body-content>emptybody-content>
  tag>


④. 在 JSP 页面上使用自定义标签:

> 使用 taglib 指令导入标签库描述文件: <%@taglib uri="http://www.atguigu.com/mytag/core" prefix="atguigu" %>

> 使用自定义的标签:

<%@ 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 heretitle>
head>
<body>
    
    <atguigu:hello />
    
body>
html>

 

使用自定义标签的JSP和tld 文件的对应:

JavaWeb(七):EL表达式、自定义标签和JSTL_第1张图片

 

 

 

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 heretitle>
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">

    
    <description>MyTag 1.0 core librarydescription>
    <display-name>MyTag coredisplay-name>
    <tlib-version>1.0tlib-version>

    
    <short-name>atguigushort-name>
    
    <uri>http://www.atguigu.com/mytag/coreuri>

    
    <tag>
        
        <name>helloname>

        
        <tag-class>com.atguigu.javaweb.tag.HelloSimpleTagtag-class>
        
        <body-content>emptybody-content>

        
        <attribute>
            
            <name>valuename>
            
            <required>truerequired>
            
            <rtexprvalue>truertexprvalue>
        attribute>

        <attribute>
            <name>countname>
            <required>falserequired>
            <rtexprvalue>falsertexprvalue>
        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("
"); } } @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>
    
    <name>valuename>
    
    <required>truerequired>
    
    <rtexprvalue>truertexprvalue>
attribute>

③. 在页面中使用属性, 属性名同 tld 文件中定义的名字.

<atguigu:hello value="${param.name }" count="10"/>

 

练习

定制一个带有两个属性的标签, 用于计算并输出两个数的最大值

 

实现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;
    }   
}

 

JavaWeb(七):EL表达式、自定义标签和JSTL_第2张图片

 

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>abcdefgatguigu: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 heretitle>
head>
<body>

<aidata:testJspFragment>HelloWorldaidata: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">

    
    <description>MyTag 1.2 core librarydescription>
    <display-name>MyTag coredisplay-name>
    <tlib-version>1.0tlib-version>

    
    <short-name>aidatashort-name>
    
    <uri>http://www.aidata.com/mytag/coreuri>

    
    <tag>
        
        <name>testJspFragmentname>

        
        <tag-class>com.aidata.web.TestJspFragmenttag-class>
        
        <body-content>scriptlessbody-content>
    tag>

taglib>

在 tld 文件中, 使用 body-content 节点来描述标签体的类型:

: 指定标签体的类型, 大部分情况下, 取值为 scriptless。可能取值有 3 种:

  • empty: 没有标签体
  • scriptless: 标签体可以包含 el 表达式和 JSP 动作元素,但不能包含 JSP 的脚本元素
  • tagdependent: 表示标签体交由标签本身去解析处理。

若指定 tagdependent,在标签体中的所有代码都会原封不动的交给标签处理器,而不是将执行结果传递给标签处理器

<body-content>tagdependentbody-content>

 

练习

定义一个自定义标签: abcdefg 把标签体内容转换为大写,并输出 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 + "
"); } } }

配置tld

    <tag>
        
        <name>printUppername>

        
        <tag-class>com.aidata.web.PrintUpperTagtag-class>
        
        <body-content>scriptlessbody-content>
        <attribute>
            <name>timename>
            <required>truerequired>
            <rtexprvalue>truertexprvalue>
        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 heretitle>
head>
<body>

<aidata:printUpper time="10">abcdefgaidata: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 heretitle>
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>
        
        <name>forEachname>

        
        <tag-class>com.aidata.web.ForEachTagtag-class>
        
        <body-content>scriptlessbody-content>
        <attribute>
            <name>itemsname>
            <required>truerequired>
            <rtexprvalue>truertexprvalue>
        attribute>
         <attribute>
            <name>varname>
            <required>truerequired>
            <rtexprvalue>truertexprvalue>
        attribute>
    tag>

jsp

    

    <aidata:forEach items="${requestScope.customers }" var="cust">
         ${cust.id } -- ${cust.name } <br>
    aidata:forEach>

 

2.4 带父标签的自定义标签

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

test.jsp

    
    <aidata:parentTag>
        
        <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 的. 实际使用需要进行类型的强制转换.

JavaWeb(七):EL表达式、自定义标签和JSTL_第3张图片

 

 

 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 配置文件中,无需为父标签有额外的配置。但子标签是是以标签体的形式存在的, 所以父标签的 需设置为 scriptless

    <tag>
        
        <name>parentTagname>

        
        <tag-class>com.aidata.web.ParentTagtag-class>
        
        <body-content>scriptlessbody-content>
    tag>
    <tag>
        
        <name>sonTagname>

        
        <tag-class>com.aidata.web.SonTagtag-class>
        
        <body-content>emptybody-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

    
        ^大学毕业
        ^高中毕业
        ^高中以下...
    

 

tld

    <tag>
        <name>choosename>
        <tag-class>com.aidata.web.ChooseTagtag-class>
        <body-content>scriptlessbody-content>
    tag>
    
    <tag>
        <name>whenname>
        <tag-class>com.aidata.web.WhenTagtag-class>
        <body-content>scriptlessbody-content>
        
        <attribute>
            <name>testname>
            <required>truerequired>
            <rtexprvalue>truertexprvalue>
        attribute>
    tag>
    
    <tag>
        <name>otherwisename>
        <tag-class>com.aidata.web.OtherwiseTagtag-class>
        <body-content>scriptlessbody-content>
    tag>

 

EL自定义函数

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

引入

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

使用

    
    ${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 文件中描述自定义函数
    •     
          <function>    
              <name>concatname>
              <function-class>com.atguigu.javaweb.MyELFunctionfunction-class>
              <function-signature>java.lang.String concat(java.lang.String, java.lang.String)function-signature>
          function>
  • 在 JSP 页面中导入和使用自定义函数
  •     
        ${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操作。

JavaWeb(七):EL表达式、自定义标签和JSTL_第4张图片

 

3.1  表达式操作

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

语法

JavaWeb(七):EL表达式、自定义标签和JSTL_第5张图片

 

 属性

JavaWeb(七):EL表达式、自定义标签和JSTL_第6张图片

 

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

一般来说,默认会将 <、>、’、” 和 & 转换为 <、>、'、" 和 &。假若不想转换时,只需要设定的escapeXml 属性为fasle 就可以了

 

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

out则可以自动的转换

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

 

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

语法

JavaWeb(七):EL表达式、自定义标签和JSTL_第7张图片

 

                          语法3:

JavaWeb(七):EL表达式、自定义标签和JSTL_第8张图片

 

 

JavaWeb(七):EL表达式、自定义标签和JSTL_第9张图片

 

使用时,var 主要用来存放表达式的结果;scope 则是用来设定储存的范围,例如:假若scope="session",则将会把数据储存在session中。如果中没有指定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 }
<c:set target="${requestScope.cust }" property="id" value="${param.id }">c:set> <br> ID: ${requestScope.cust.id }

 

主要用来移除变量。

语法

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

属性

 

 

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

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

将number 变量从Session 范围中移除。若我们不设定scope,则将会从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 流程控制

流程控制分类中包含四个标签:


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

语法

JavaWeb(七):EL表达式、自定义标签和JSTL_第10张图片

 

 属性

JavaWeb(七):EL表达式、自定义标签和JSTL_第11张图片

 

  标签必须要有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>

 


本身只当做 的父标签。

语法

JavaWeb(七):EL表达式、自定义标签和JSTL_第12张图片

的本体内容只能有:

  • ·空白
  • ·1 或多个
  • ·0 或多个

若使用来做流程控制时,两者都必须为的子标


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

语法

JavaWeb(七):EL表达式、自定义标签和JSTL_第13张图片

 

 属性

JavaWeb(七):EL表达式、自定义标签和JSTL_第14张图片

 

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


在同一个 中,当所有 的条件都没有成立时,则执行 的本体内容。

语法

必须在 之间,在同一个 中时, 必须为最后一个标签。在同一个 中,假若所有 的test 属性都不为true 时,则执行 的本体内容。

<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 迭代操作


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

语法

JavaWeb(七):EL表达式、自定义标签和JSTL_第15张图片

属性

JavaWeb(七):EL表达式、自定义标签和JSTL_第16张图片

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

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

Null 和错误处理

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

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


    <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> 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 操作有关的标签,它们分别为:。它们主要的功能是:用来将其他文件的内容包含起来、网页的导向,还有url 的产生。

 


主要用来产生一个URL。

语法

JavaWeb(七):EL表达式、自定义标签和JSTL_第17张图片

属性

JavaWeb(七):EL表达式、自定义标签和JSTL_第18张图片

 

 

    <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 转发到指定页面可以使用
        <%--  
        ="/test.jsp">jsp:forward>    
        --%>
        / 代表的是当前 WEB 应用的根目录. 
        
        response.sendRedirect("/test.jsp") / 代表 WEB 站点的根目录
    h4>
    <%-- 
    ="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>

 

 

 

 

 

 

 

 

  

你可能感兴趣的:(JavaWeb(七):EL表达式、自定义标签和JSTL)