Javaweb之jstl详解

Javaweb之jstl详解

1. JSTL标签库概述

1.1. 什么是JSTL标签库

JSTL全称为JSP Standard Tag Library,即JSP标准标签库。JSTL最初是一套Java官方的标签库解决方案,自从JavaEE 5之后被定义为标准的标签库。JSTL规范由Sun公司定制,Apache的Jakarta小组负责实现,目前的版本是JSTL1.2。

EL最初定义在JSTL1.0规范中,在JSP2.0之后,EL已经正式成为JSP规范的一部分。在JSTL1.1规范中,已经没有了EL的内容,不过在JSTL中仍然可以使用EL。

JSTL的目标是为了简化JSP页面的设计,JSTL的使用为页面设计人员和程序开发人员的分工协作提供了便利。

JSTL虽然叫做标准标签库,但实际上是由五个不同功能的标签库组成的。分别为core标签库、fmt标签库、SQL标签库、XML标签库及Functions标签库,其中Functions标签库就是前面提到了EL表达式的函数库,下面主要学习core标签库和fmt标签库。

1.2. 百度百科

JSTL(JSP Standard Tag Library,JSP标准标签库)是一个不断完善的开放源代码的JSP标签库,是由apache的jakarta小组来维护的。JSTL只能运行在支持JSP1.2和Servlet2.3规范的容器上,如tomcat 4.x。在JSP 2.0中也是作为标准支持的。

JSTL 1.0 发布于 2002 年 6 月,由四个定制标记库(core、format、xml 和 sql)和一对通用标记库验证器(ScriptFreeTLV 和 PermittedTaglibsTLV)组成。core 标记库提供了定制操作,通过限制了作用域的变量管理数据,以及执行页面内容的迭代和条件操作。它还提供了用来生成和操作 URL 的标记。顾名思义,format 标记库定义了用来格式化数据(尤其是数字和日期)的操作。它还支持使用本地化资源束进行 JSP 页面的国际化。xml 库包含一些标记,这些标记用来操作通过 XML 表示的数据,而 sql 库定义了用来查询关系数据库的操作。

如果要使用JSTL,则必须将jstl.jar和 standard.jar文件放到classpath中,如果你还需要使用XML processing及Database access (SQL)标签,还要将相关JAR文件放到classpath中,这些JAR文件全部存在于下载回来的zip文件中。

1.3. 维基百科

JSP标准标签库(JSP Standard Tag Library)是Java EE网络应用程序开发平台的组成部分。它在JSP规范的基础上,扩充了一个JSP的标签库来完成一些通用任务,比如XML数据处理、条件执行、数据库访问、循环和国际化。

JSTL是在JCP下,作为JSR 52被开发出来的。2006年5月8日发布了JSTL 1.2,接下来是2011年12月7日的JSTL 1.2.1。

JSTL提供了一个有效的途径,以在JSP页面中嵌入逻辑,而不是直接嵌入Java代码。使用标准标签集,减少了Java代码导致的不连续,从而提高代码的可维护性,并达到应用软件代码开发与用户界面间的关注点分离。

2. JSTL的core标签库

2.1. <c:out>标签

<c:out>标签用于计算一个表达式并将结果输出到当前的JspWriter对象。<c:out>标签的功能类似于JSP的表达式<%=expression%>。

<c:out>标签的语法格式如下:

<c:out value="表达式" escapeXml="是否转义" default="默认值"></c:out>
  • value属性:指定被计算的表达式。
  • escapeXml属性:确定在结果字符中的字符“<”、“>”、“’”、“””和“&”是否应该被转换为对应的字符引用或预定义实体引用,默认值为true。

如果值为true,那么字符“<”、“>”、“’”、“””和“&”将按照如下表进行转换。

字符字符实体代码
<&lt;
>&gt;
>‘&#039;
&#034;
&&amp;
  • default属性:如果value为null,那么将使用这个默认值。

下面是<c:out>标签的具体用法:

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title> out.jsp </title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
    <%
        pageContext.setAttribute("name", "longestory");
    %>
    <c:out value="${name}"></c:out><br/>
    <c:out value="<script>alert('hello longestory.');</script>" escapeXml="false"></c:out><br/>
    <c:out value="${helloworld}" default="unknown"></c:out>
  </body>
</html>

[复制代码](javascript:void(0)😉

2.2. <c:set>标签

<c:set>标签用于设置范围变量的值或者JavaBean对象的属性。

<c:set>标签的语法格式如下:

<c:set var="变量名称" value="表达式" scope="JSP域范围"></c:set>
  • var属性:将value属性计算表达式得到的结果,保存在该变量名称中。
  • value属性:指定被计算的表达式。
  • scope属性:var属性指定的变量所使用的范围(JSP域范围)。
  • target属性:要设置属性的对象。必须是JavaBean对象(对应的属性有setter方法)或者java.util.Map对象。
  • property属性:要设置的target对象的属性名称。

下面是<c:set>标签的具体用法:

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>set.jsp</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
    <c:set var="name" value="longestory" scope="session"></c:set>
    <c:out value="name"></c:out>
    <br>
    <jsp:useBean id="user" class="app.java.bean.User" scope="session" />
    <c:set target="${user }" property="age" value="18"></c:set>
    <c:out value="${user.age }"></c:out>
  </body>
</html>

[复制代码](javascript:void(0)😉

2.3. <c:remove>标签

<c:remove>标签用于移除指定范围的变量。

<c:remove>标签的语法格式如下:

<c:remove var="变量名称" scope="JSP域范围"/>
  • var属性:要移除指定范围的变量名称。
  • scope属性:var属性指定的变量的范围(JSP域),默认是page。

下面是<c:remove>标签的具体用法:

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>remove.jsp</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
    <%
        pageContext.setAttribute("a", "pageContext");
        request.setAttribute("a", "session");
        session.setAttribute("a", "session");
        application.setAttribute("a", "application");
    %>
    <!-- 删除所有域中的name为a的数据 -->
    <c:remove var="a"/>
    <c:out value="${a }" default="none"/>
  </body>
</html>

[复制代码](javascript:void(0)😉

2.4. <c:if>标签

<c:if>标签用于实现Java语言中的if语句的功能。

<c:if>标签的语法格式如下:

<c:if test="条件" var="变量名称" scope="JSP域范围"></c:if>
  • test属性:测试的条件,用于判断标签体是否应该被执行。
  • var属性:将测试条件的结果值保存在该变量中,该变量的值类型为Boolean。
  • scope属性:var属性指定变量的JSP域范围,默认值为page。

下面是<c:if>标签的具体用法:

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>if.jsp</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
    <c:set var="name" value="longestory"/>
    <c:if test="${not empty name }" var="test" scope="session">
        <c:out value="${name }"/>
    </c:if>
    <br>
    <c:if test="${test }">
        <c:out value="helloworld"></c:out>
    </c:if>
  </body>
</html>

[复制代码](javascript:void(0)😉

2.5. <c:choose>标签

<c:choose>标签、<c:when>标签和<c:otherwise>标签一起实现互斥条件的执行,类似于Java语言的if/else if/else语句。

<c:choose>标签、<c:when>标签和<c:otherwise>标签的语法格式如下:

<c:choose>
   <c:when test="条件"></c:when>
   <c:otherwise></c:otherwise>
</c:choose>

下面是<c:choose>标签、<c:when>标签和<c:otherwise>标签的具体用法:

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>choose.jsp</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
     <c:set var="c" value="${param.score }"/>
     <c:choose>
         <c:when test="${c > 100 || c < 0 }">输入有误,请输入正确的成绩:0~100之间。</c:when>
         <c:when test="${c >= 90 }">A</c:when>
         <c:when test="${c >= 80 }">B</c:when>
         <c:when test="${c >= 70 }">C</c:when>
         <c:when test="${c >= 60 }">D</c:when>
         <c:otherwise>E</c:otherwise>
     </c:choose>
  </body>
</html>

[复制代码](javascript:void(0)😉

2.6. <c:url>标签

<c:url>标签使用正确的URL重写规则构造一个URL。

<c:url>标签的语法格式如下:

<c:url value="url路径" var="变量名称" scope="JSP域范围"></c:url>
  • value属性:要处理的URL。
  • var属性:将处理的URL保存在该变量中,该变量的类型为String。
  • scope属性:var属性指定变量的JSP域范围,默认值为page。

下面是<c:url>标签的具体用法:

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>url.jsp</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
     <a href="<c:url value='/servlet/AServlet'/>">链接1</a><br/>
     <c:url value="/servlet/AServlet" var="url" scope="request">
         <c:param name="username" value="longestory" />
         <c:param name="password" value="123" />
     </c:url>
     <a href="${requestScope.url }">链接2</a>
  </body>
</html>

[复制代码](javascript:void(0)😉

2.7. <c:forEach>标签

<c:forEach>标签用于对包含了多个对象的集合进行迭代,重复执行它的标签体,或者重复迭代固定的次数。

<c:forEach>标签的语法格式如下:

<c:forEach var="变量名称" begin="起始位置" end="截至位置" step="步长" items="集合对象" varStatus="迭代状态"></c:forEach>
  • var属性:用于迭代的变量名称。
  • begin属性:指定迭代的起始位置。
  • end属性:指定迭代的截至位置。
  • step属性:迭代的步长,默认的步长是1。
  • items属性:要迭代的集合对象。
  • varStatus属性:要迭代的状态,可以获取迭代过程中的一些状态。

对于<c:forEach>标签的实际用法,大体分为两种:

  • 循环变量,指定开始和结束位置(计数):

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>foreach.jsp</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
    <c:forEach var="i" begin="1" end="10">
        ${i }<br/>
    </c:forEach>
    <br/>
    <c:set var="sum" value="0"/>
    <c:forEach var="i" begin="1" end="100">
        <c:set var="sum" value="${sum + i }"/>
    </c:forEach>
    sum = ${sum }
  </body>
</html>

[复制代码](javascript:void(0)😉

  • 循环遍历集合,其中包含数组、List或Map集合等:

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>foreach.jsp</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
    <%
        String[] arr = {"one", "two", "three"};
        pageContext.setAttribute("arr", arr);
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("c");
        pageContext.setAttribute("abc", list);
        
        Map<String,String> person = new LinkedHashMap<String,String>();
        person.put("name", "zhangSan");
        person.put("age", "23");
        person.put("sex", "male");
        
        pageContext.setAttribute("p", person);
    %>
    <c:forEach items="${arr }" var="str">
        ${str }<br/>
    </c:forEach>
    <br/>
    <c:forEach items="${abc }" var="str">
        ${str }<br/>
    </c:forEach>
    <br/>
    <c:forEach items="${p }" var="entry">
        ${entry.key } = ${entry.value }<br/>
    </c:forEach>
  </body>
</html>

[复制代码](javascript:void(0)😉

  • 在迭代中通过varStatus属性获取迭代中的状态。

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>foreach.jsp</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
    <c:forEach items="${arr }" var="str" varStatus="vs">
        first: ${vs.first }, last: ${vs.last }, count: ${vs.count }, index: ${vs.index }, current: ${vs.current }<br/>
    </c:forEach>
  </body>
</html>

[复制代码](javascript:void(0)😉

3. 自定义标签

3.1. 为什么要自定义

JSP中设计自定义标签的目的就是为了实现HTML代码重用。自定义标签可以实现非常复杂的功能,但使用起来很简单。

在JavaEE规范中,是不建议在JSP页面直接编写Java代码的,而是通过自定义标签来调用对应的Java代码实现某些功能。因为企业的业务需求是多种多样的,常见的开源框架只能提供通用的Java代码功能。如果要实现既定业务逻辑功能,就可以通过自定义标签方式解决。

3.2. 自定义标签步骤

在JavaEE的API中提供了Tag接口,我们可以通过实现该接口,完成自定义标签的功能。Tag接口在API中提供了如下几种方法,实现该接口时需要重写这几种方法:

Method Summary
intdoEndTag() Process the end tag for this instance.
intdoStartTag() Process the start tag for this instance.
TaggetParent() Get the parent (closest enclosing tag handler) for this tag handler.
voidrelease() Called on a Tag handler to release state.
voidsetPageContext(PageContext pc) Set the current page context.
voidsetParent(Tag t) Set the parent (closest enclosing tag handler) of this tag handler.

自定义标签的创建具体步骤如下:

  • 创建一个Java类实现Tag接口,该类完成自定义标签的具体逻辑功能。

[复制代码](javascript:void(0)😉

public class OneTag implements Tag {
    public void setPageContext(PageContext pc) {
        System.out.println("这是setPageContext()方法...");
    }
    public void setParent(Tag t) {
        System.out.println("这是setParent()方法...");
    }
    public Tag getParent() {
        System.out.println("这是getParent()方法...");
        return null;
    }
    public int doStartTag() throws JspException {
        System.out.println("这是doStartTag()方法...");
        return 0;
    }
    public int doEndTag() throws JspException {
        System.out.println("这是doEndTag()方法...");
        return 0;
    }
    public void release() {
        System.out.println("这是release()方法...");
    }
}

[复制代码](javascript:void(0)😉

  • 在Web工程目录的WEB-INF目录中,创建tld自定义标签的描述文件。

[复制代码](javascript:void(0)😉

<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" 
        xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">
 <!-- 定义自定义标签库的版本 -->
 <tlib-version>1.0</tlib-version>
 <!-- 定义自定义标签库的名称 -->
 <short-name>ls</short-name>
 <!-- 定义自定义标签库的URI -->
 <uri>http://www.mytag.com/tags/onetag</uri>
 <!-- 添加自定义标签 -->
 <tag>
     <!-- 定义自定义标签的名称 -->
     <name>onetag</name>
     <!-- 定义自定义标签对应的类的完整路径 -->
     <tag-class>app.java.tags.OneTag</tag-class>
     <!-- 
         定义自定义标签内允许包含哪些内容,备选项如下:
         * empty:表示当前自定义标签内,不能包含任何内容.(空标签)
         * jsp:表示当前自定义标签内,可以包含有关JSP页面的所有内容.
         * scriptless:表示当前自定义标签内,不能包含JSP脚本内容.(具体指JSP脚本<%%>)
         * tagdependent:表示当前自定义标签仅供服务器端使用,不能为客户端页面提供显示.
     -->
     <body-content>empty</body-content>
 </tag>
</taglib>

[复制代码](javascript:void(0)😉

  • 在JSP页面中引入自定义标签库。

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="ls" uri="/WEB-INF/mytags/onetag.tld" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>onetag.jsp</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
    <ls:onetag/>
  </body>
</html>

[复制代码](javascript:void(0)😉

3.3. 自定义标签继承链

虽然目前可以通过实现Tag接口,完成自定义标签的功能,但是很麻烦。下面来研究一下Tag接口的继承链关系,如下图所示:

img

通过查看Tag接口的继承链关系,可以发现如下内容:

  • Tag接口具有一个父级接口,叫做JspTag接口。Tag接口是JSP1.2规范定义的接口,JspTag接口是JSP2.0规范定义的接口,通过实现Tag接口的自定义标签被称之为传统标签。目前更多使用是JSP2.0规范。
  • Tag接口具有两个子接口IterationTag接口和BodyTag接口,这两个接口分别有TagSupport实现类和BodyTagSupport实现类。具体自定义标签时,实际上是通过继承这两个实现类完成的,而不是实现Tag接口或其两个子接口完成。
  • JspTag接口具有另一个子接口SimpleTag接口。通过实现SimpleTag接口的自定义标签被称之为简单标签,但实际上只是实现过程变得更为简单而已。该接口具有一个实现类SimpleTagSupport类,实现自定义标签时是通过继承该类完成的。

3.4. 自定义简单标签

掌握了Tag接口的继承链关系后,在今后的实际开发中,更多是自定义简单标签。要想实现自定义简单标签,要么实现SimpleTag接口,要么继承SimpleTagSupport类。具体实现步骤如下:

  • 创建一个Java类继承SimpleTagSupport类,重写doTag()方法。

[复制代码](javascript:void(0)😉

public class TwoTag extends SimpleTagSupport {
    @Override
    /**
     * 当执行到自定义标签时,调用该方法
     */
    public void doTag() throws JspException, IOException {
        //1 获取pageContext对象
        PageContext pageContext = (PageContext)this.getJspContext();
        //2 通过pageContext对象获取out内置对象
        JspWriter out = pageContext.getOut();
        //3 通过out内置对象向页面输出内容
        out.println("<h1>hello tags.</h1>");
    }
}

[复制代码](javascript:void(0)😉

  • 在Web工程目录的WEB-INF目录中,创建tld自定义标签的描述文件。

[复制代码](javascript:void(0)😉

<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" 
        xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
         http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">
<tlib-version>1.0</tlib-version>
<short-name>ls</short-name>
<uri>http://www.longestory.com/tags/onetag</uri>
<tag>
     <name>twotag</name>
     <tag-class>app.java.tags.TwoTag</tag-class>
     <body-content>empty</body-content>
 </tag>
</taglib>

[复制代码](javascript:void(0)😉

  • 在JSP页面中引入自定义标签库。

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="ls" uri="/WEB-INF/mytags/mytags.tld" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>twotag.jsp</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
    <ls:twotag/>
  </body>
</html>

[复制代码](javascript:void(0)😉

3.5. 简单标签的生命周期

到目前为止,通过Tag接口和SimpleTagSupport类分别实现了传统自定义标签和简单自定义标签两种,下面跟深入地了解一下自定义标签的生命周期。

首先,先来讨论传统标签的生命周期(以上面的传统自定义标签为例)。

  • 自定义传统标签类
  • 该自定义标签类的构造函数只被调用一次,说明该自定义标签类是单实例的。
  • 每次执行标签,会调用setPageContext()方法。该方法用于向自定义标签类传递pageContext内置对象(通过该对象可以获取其他八个内置对象)。
  • setPageContext()方法被调用后,调用setParent()方法。该方法用于向当前自定义标签类传递一个父标签内容,例如<c:choose>标签内使用的<c:when>标签。
  • 最后调用的是doStartTag()方法和doEndTag()方法,分别用于开始执行标签和结束执行标签,自定义标签具体实现的逻辑功能封装在这两个方法中。
  • tomcat结束时调用release()方法。该方法用于释放创建自定义标签所用的资源。

下面,查看SimpleTag接口的API方法内容,如下表:

Method Summary
voiddoTag() Called by the container to invoke this tag.
JspTaggetParent() Returns the parent of this tag, for collaboration purposes.
voidsetJspBody(JspFragment jspBody) Provides the body of this tag as a JspFragment object, able to be invoked zero or more times by the tag handler.
voidsetJspContext(JspContext pc) Called by the container to provide this tag handler with the JspContext for this invocation.
voidsetParent(JspTag parent) Sets the parent of this tag, for collaboration purposes.

根据SimpleTag接口提供的方法,来讨论简单标签的生命周期(以上面的简单自定义标签为例)。

  • 向自定义简单标签类,增加构造函数、setParent()方法、setJspContext()方法和setJspBody()方法。

[复制代码](javascript:void(0)😉

public class TwoTag extends SimpleTagSupport {
    public TwoTag() {
        System.out.println("这是TwoTag方法...");
    }
    @Override
    public void setParent(JspTag parent) {
        System.out.println("这是setParent方法...");
    }
    @Override
    public void setJspContext(JspContext pc) {
        System.out.println("这是setJspContext方法...");
    }
    @Override
    public void setJspBody(JspFragment jspBody) {
        System.out.println("这是setJspBody方法...");
    }
    @Override
    public void doTag() throws JspException, IOException {
        System.out.println("这是doTag方法...");
    }
}

[复制代码](javascript:void(0)😉

    • 每次执行自定义标签时,构造函数都被调用一次,说明自定义简单标签类是多实例的。
    • 自定义标签被执行时,调用setJspContext()方法。该方法用于向自定义标签类传递pageContext内置对象(通过该对象可以获取其他八个内置对象)。
    • 调用setJspContext()方法后,调用doTag()方法。该方法用于封装自定义标签具体实现的逻辑功能。
    • setParent()方法:用于向当前自定义标签传递父标签内容,例如<c:choose>标签内使用的<c:when>标签。如果没有传递父标签,则为null值。
    • setJspBody()方法:用于向当前自定义标签传递JSP内容。因为配置自定义标签时使用了EMPTY,所以没有被调用。
    • 自定义简单标签并没有像传统标签一样的release()释放资源的方法。

3.6. 带标签体的简单标签

上述实现的自定义简单标签只是最基本的用法,简单标签在自定义时,还可以定义标签体内容。具体实现步骤如下:

  • 创建一个Java类继承SimpleTagSupport类,重写doTag()方法。

[复制代码](javascript:void(0)😉

public class ThreeTag extends SimpleTagSupport {
    @Override
    public void doTag() throws JspException, IOException {
        //1 获取pageContext对象
        PageContext pageContext = (PageContext) this.getJspContext();
        //2 通过pageContext对象获取out内置对象
        JspWriter out = pageContext.getOut();
        //3 创建输出流对象
        StringWriter writer = new StringWriter();
        //4 获取标签体内容,为JspFragment类型
        JspFragment body = this.getJspBody();
        /*
         * 5 通过invoke()方法将标签体输出到指定的writer中
         *  * 如果writer参数为null,将输出到默认的writer中.即getJspContext().getOut()
         */
        body.invoke(writer);
        //6 打印标签体内容 
        out.println(writer.getBuffer().toString().toUpperCase());
    }
}

[复制代码](javascript:void(0)😉

  • 在Web工程目录的WEB-INF目录中,创建tld自定义标签的描述文件。

[复制代码](javascript:void(0)😉

<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" 
        xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
         http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">
<tlib-version>1.0</tlib-version>
<short-name>ls</short-name>
<uri>http://www.mytag.com/tags/onetag</uri>
<tag>
     <name>threetag</name>
     <tag-class>app.java.tags.ThreeTag</tag-class>
     <!-- 定义自定义简单标签时,不能使用JSP选项. -->
     <body-content>tagdependent</body-content>
 </tag>
</taglib>

[复制代码](javascript:void(0)😉

  • 在JSP页面中引入自定义标签库。

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="ls" uri="/WEB-INF/mytags/mytags.tld" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>threetag.jsp</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
    <ls:threetag>
        this is mytag.
    </ls:threetag>
  </body>
</html>

[复制代码](javascript:void(0)😉

3.7. 带属性的简单标签

除了可以实现带标签体的自定义简单标签外,还可以实现带属性的自定义简单标签,具体实现步骤如下:

  • 创建一个Java类继承SimpleTagSupport类,重写doTag()方法。

[复制代码](javascript:void(0)😉

public class FourTag extends SimpleTagSupport {
    private Boolean test;
    public Boolean getTest() {
        return test;
    }
    public void setTest(Boolean test) {
        this.test = test;
    }
    @Override
    public void doTag() throws JspException, IOException {
        if(test){
            this.getJspBody().invoke(null);
        }
    }
}

[复制代码](javascript:void(0)😉

  • 在Web工程目录的WEB-INF目录中,创建tld自定义标签的描述文件。

[复制代码](javascript:void(0)😉

<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" 
        xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
         http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">
<tlib-version>1.0</tlib-version>
<short-name>ls</short-name>
<uri>http://www.mytag.com/tags/onetag</uri>
<tag>
     <name>fourtag</name>
     <tag-class>app.java.tags.FourTag</tag-class>
     <body-content>scriptless</body-content>
     <!-- 为自定义简单标签配置一个属性 -->
     <attribute>
         <!-- 定义该属性名称 -->
         <name>test</name>
         <!-- 定义该属性是否必要 -->
         <required>true</required>
         <!-- 定义该属性是否允许EL表达式或JSTL标签等 -->
         <rtexprvalue>true</rtexprvalue>
     </attribute>
 </tag>
</taglib>

[复制代码](javascript:void(0)😉

  • 在JSP页面中引入自定义标签库。

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="ls" uri="/WEB-INF/mytags/mytags.tld" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>fourtag.jsp</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
    <ls:fourtag test="${param.flag }">
        this is mytag.
    </ls:fourtag>
  </body>
</html>

[复制代码](javascript:void(0)😉

3.8. 其他情况的简单标签

除了自定义简单标签带有标签体和属性之外,简单标签还可以实现很多功能。例如在执行完自定义简单标签后,JSP页面后面的内容不再执行等功能。下面就来实现一下这个功能,具体实现步骤如下:

  • 创建一个Java类继承SimpleTagSupport类,重写doTag()方法。

[复制代码](javascript:void(0)😉

public class FiveTag extends SimpleTagSupport {
    @Override
    public void doTag() throws JspException, IOException {
        this.getJspContext().getOut().println("下面的内容都是不显示的.");
        throw new SkipPageException();
    }
}

[复制代码](javascript:void(0)😉

  • 在Web工程目录的WEB-INF目录中,创建tld自定义标签的描述文件。

[复制代码](javascript:void(0)😉

<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" 
        xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
         http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">
<tlib-version>1.0</tlib-version>
<short-name>ls</short-name>
<uri>http://www.mytag.com/tags/onetag</uri>
 <tag>
     <name>fivetag</name>
     <tag-class>app.java.tags.FiveTag</tag-class>
     <body-content>empty</body-content>
 </tag>
</taglib>

[复制代码](javascript:void(0)😉

  • 在JSP页面中引入自定义标签库。

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="ls" uri="/WEB-INF/mytags/mytags.tld" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>fivetag.jsp</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
    <ls:fivetag/>
    
    <p>人从来到这个世界上,就注定着最终要离开。
  </body>
</html>

[复制代码](javascript:void(0)😉

3.9. 打包自定义标签库

自定义标签,无论是传统标签还是简单标签,都是为了将来开发JSP页面更加简单。而目前自定义的标签只能在当前Web工程中使用,其他Web工程并不能使用。为了可以让其他Web工程也可以使用自定义标签库内容,需要将自定义标签打包成JAR包。具体操作步骤如下:

  • 创建一个Java工程,方便打包。
  • 在当前Java工程的根目录中,右键创建一个目录为“META-INF”。
  • 将tld自定义标签描述文件,拷贝到“META-INF”目录中。
  • 将对应自定义标签类拷贝到当前Java工程的“src”目录中。
  • 当将自定义标签类拷贝到“src”目录中后,会报错。原因是Java工程中没有JavaEE所需的JAR包。
  • 需要为当前Java工程导入JavaEE所需的JAR包即可。
  • 将当前Java工程导出为JAR包即可。

4. 国际化

4.1. 什么是国际化

如果一个系统或软件在某个国家或地区使用时,采用该国家或地区的语言、数字、货币和日期等习惯,将这种方式称之为资源本地化。开发系统或软件时,可以支持多个国家或地区的本地化应用,就可以叫做资源国际化。

所谓资源国际化,并不是简单提供几套不同语言的软件系统就能解决的,是一个很复杂的问题。而Java提供了资源绑定ResourcesBundle、地区Locale、时区TimeZone等支持资源国际化。资源国际化有两个常用的术语I18N与I10N。

  • I18N即资源国际化,全称为Internationalization,因为首字母I与末字母N之间共18个字母,又称I18N。通俗地讲,资源国际化就是要让这个系统或软件使用国际环境,如语言、数字、货币和日期等。
  • I10N为资源本地化,全称为Localization,因为首字母I与末字母N之间共10个字母,又称I10N。资源本地化就是要让这个系统或软件使用当地环境,如语言、数字、货币和日期等。

4.2. 如何国际化

让一个系统或软件实现本地化不难,但想要实现国际化还是有一些难度的。下面先来学习Java中提供的实现国际化功能的方式,具体内容如下:

  • Web

    工程的“

    src

    ”根目录下创建国际化资源文件。

    • 国际化默认的资源文件命名方式为“资源文件名称.properties”。
name=default longestory
    • 如果创建对应本地化资源文件的话,命名方式为“资源文件名称_语言代码_国家代码.properties”。下面分别为英文资源文件和中文资源文件,其中中文资源文件的编码为ISO-8859-1。
name=longestory
name=\u9F99\u54E5\u6709\u8BDD\u8BF4
  • 创建一个Java文件,用于读取国际化资源文件,进行测试。

[复制代码](javascript:void(0)😉

public class ResourceBundleTest {
    @Test
    // 与访问用户默认的语言和国家匹配
    public void demo(){
        // 通过ResourceBundle类的getBundle(默认国际化资源文件名称)方法读取国际化资源文件
        ResourceBundle bundle = ResourceBundle.getBundle("info");
        // 通过ResourceBundle对象的的getString(key)获取value
        String value = bundle.getString("name");
        // 测试打印
        System.out.println(value);
    }
}

[复制代码](javascript:void(0)😉

如果想要获取指定国家和语言的国际化资源文件,可以如下来完成。

  • 创建一个Java文件,用于读取国际化资源文件,进行测试。

[复制代码](javascript:void(0)😉

public class ResourceBundleTest {
    @Test
    public void demo2(){
        // 通过ResourceBundle类的getBundle(默认国际化资源文件名称)方法读取国际化资源文件
        ResourceBundle bundle = ResourceBundle.getBundle("info",Locale.US);
        // 通过ResourceBundle对象的的getString(key)获取value
        String value = bundle.getString("name");
        // 测试打印
        System.out.println(value);
    }
}

[复制代码](javascript:void(0)😉

4.3. 日期国际化

除了文本信息需要国际化以外,日期也需要国际化,可以使用Java提供的java.text.DateFormat类来完成。首先,来参考一下Java提供的API文档,需要用到DateFormat类的哪些方法:

方法摘要
static DateFormat[getDateInstance](https://www.cnblogs.com/aaron911/p/7799767.html#getDateInstance(int, java.util.Locale))(int style, Locale aLocale) 获得日期 formatter,该 formatter 具有给定语言环境的给定格式化风格。
static DateFormat[getDateTimeInstance](https://www.cnblogs.com/aaron911/p/7799767.html#getDateTimeInstance(int, int, java.util.Locale))(int dateStyle, int timeStyle, Locale aLocale) 获得日期/时间 formatter,该 formatter 具有给定语言环境的给定格式化风格。
static DateFormat[getTimeInstance](https://www.cnblogs.com/aaron911/p/7799767.html#getTimeInstance(int, java.util.Locale))(int style, Locale aLocale) 获得时间 formatter,该 formatter 具有给定语言环境的给定格式化风格。

创建一个Java类,用于获取日期和时间等内容的国际化方式。

[复制代码](javascript:void(0)😉

public class DateFormatTest {
    @Test
    public void demo(){
        Date date = new Date();
        /*
         * getDateInstance(int style,Locale local):
         *  * 获得日期 formatter,该 formatter 具有给定语言环境的给定格式化风格.
         *  * style参数:表示使用的日期格式化风格,常用的选项有FULL、LONG、MEDIUM、SHORT.
         *  * local参数:指定使用的语言环境.
         */
        DateFormat dateFormat1 = DateFormat.getDateInstance(DateFormat.FULL, Locale.CHINA);
        System.out.println("日期国际化:"+dateFormat1.format(date));
        /*
         * getTimeInstance(int style,Locale local)
         *  * 获得时间 formatter,该 formatter 具有给定语言环境的给定格式化风格.
         *  * style参数:表示使用的时间格式化风格,常用的选项有FULL、LONG、MEDIUM、SHORT.
         *  * local参数:指定使用的语言环境.
         */
        DateFormat dateFormat2 = DateFormat.getTimeInstance(DateFormat.LONG, Locale.CHINA);
        System.out.println("时间国际化:"+dateFormat2.format(date));
        /*
         * getDateTimeInstance(int dateStyle, int timeStyle, Locale locale)
         *  * 获得日期/时间 formatter,该 formatter 具有给定语言环境的给定格式化风格.
         *  * dateStyle参数:表示使用的日期格式化风格,常用的选项有FULL、LONG、MEDIUM、SHORT.
         *  * timeStyle参数:表示使用的时间格式化风格,常用的选项有FULL、LONG、MEDIUM、SHORT.
         *  * local参数:指定使用的语言环境.
         */
        DateFormat dateFormat3 = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT, Locale.CHINA);
        System.out.println("日期和时间同时国际化:"+dateFormat3.format(date));
    }
}

[复制代码](javascript:void(0)😉

4.4. 数字国际化

完成日期的国际化内容后,再来完成数字的国际化方式。Java提供的java.text.NumberFormat类来完成。首先,来参考一下Java提供的API文档,需要用到NumberFormat类的哪些方法:

方法摘要
static NumberFormatgetCurrencyInstance(Locale inLocale) 返回指定语言环境的货币格式。
static NumberFormatgetIntegerInstance(Locale inLocale) 返回指定语言环境的整数格式。
static NumberFormatgetNumberInstance(Locale inLocale) 返回指定语言环境的通用数字格式。
static NumberFormatgetPercentInstance(Locale inLocale) 返回指定语言环境的百分比格式。
voidsetMaximumFractionDigits(int newValue) 设置数的小数部分的最大位数。
voidsetMaximumIntegerDigits(int newValue) 设置数的整数部分允许的最大位数。
voidsetMinimumFractionDigits(int newValue) 设置数的小数部分允许的最小位数。
voidsetMinimumIntegerDigits(int newValue) 设置数的整数部分允许的最小位数。

创建一个Java类,用于获取日期和时间等内容的国际化方式。

[复制代码](javascript:void(0)😉

public class NumberFormatTest {
    @Test
    public void demo1(){
        double i = 3.1415926;
        
        NumberFormat numberFormat1 = NumberFormat.getIntegerInstance(Locale.CHINA);
        System.out.println("指定语言环境的整数格式为:"+numberFormat1.format(i));
        
        NumberFormat numberFormat2 = NumberFormat.getNumberInstance(Locale.CHINA);
        System.out.println("指定语言环境的通用数字格式为:"+numberFormat2.format(i));
        
        NumberFormat numberFormat3 = NumberFormat.getCurrencyInstance(Locale.CHINA);
        System.out.println("指定语言环境的货币格式为:"+numberFormat3.format(i));
        
        NumberFormat numberFormat4 = NumberFormat.getPercentInstance(Locale.CHINA);
        System.out.println("指定语言环境的百分比格式为:"+numberFormat4.format(i));
    }
}

[复制代码](javascript:void(0)😉

4.5. 动态文本国际化

之前实现了文本信息的国际化,可以使用占位符实现固定文本实现动态变化。具体实现方式参考如下内容:

[复制代码](javascript:void(0)😉

public class MessageFormatTest {
    @Test
    public void demo(){
        /*
         * 作为错误信息的显示
         * String msg1 = "用户名不能为空";
         * String msg2 = "密码不能为空";
         * 
         * 所有不能为空提示信息完全一样,区别是字段名称
         */
        String pattern = "{0}不能为空";

        // 通过MessageFormat 将信息替换到占位符中
        String s1 = MessageFormat.format(pattern, "用户名");
        String s2 = MessageFormat.format(pattern, "密码");
        System.out.println(s1);
        System.out.println(s2);
    }
}

[复制代码](javascript:void(0)😉

当然,占位符不仅可以使用一个,多个占位符也是允许的,参考如下内容:

[复制代码](javascript:void(0)😉

public class MessageFormatTest {
    @Test
    public void demo(){
        String pattern = "{0}的长度必须在 {1}到{2}位数之间";
        System.out.println(MessageFormat.format(pattern, "用户名", 3, 10));
    }
}

[复制代码](javascript:void(0)😉

动态文本信息的国际化还具有很多高级用法,例如如下案例:

[复制代码](javascript:void(0)😉

public class MessageFormatTest {
    @Test
    public void demo() {
        // 动态文本高级应用
        String s = "At {0,time,short} on {0,date,medium}, a hurricance destroyed {1,number,integer} houses and caused {2,number,currency} of damage";
        // 第一个参数 日期对象12:30 pm on jul 3,1998
        Calendar calendar = Calendar.getInstance();// 日历类
        // 所有日期月份从0开始
        calendar.set(1998, 6, 3, 12, 30, 0);
        Date date = calendar.getTime();
        // 第二个参数 99
        int n = 99;
        // 第三个参数 $1000000
        int m = 1000000;

        // 指定locale 是美国
        MessageFormat messageFormat = new MessageFormat(s, Locale.US);
        System.out.println(messageFormat.format(new Object[] { date, n, m }));
    }
}

[复制代码](javascript:void(0)😉

4.6. 国际化案例

上述国际化内容都只是利用测试类完成国际化逻辑,下面利用国际化内容完成登录页面的国际化功能。具体的操作步骤如下:

  • 在Web工程的“src”根目录下创建国际化资源文件。
  • info.properties
info = default form
username = default username
password = default password
submit = default submit
  • info_en_US.properties
info = form
username = username
password = password
submit = submit
  • info_zh_CN.properties
info=\u767B\u9646\u9875\u9762
username=\u7528\u6237\u540D
password=\u5BC6\u7801
submit=\u767B\u9646
  • 创建一个JSP页面用于显示登录信息,并实现国际化。

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>login.jsp</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
    <%
        // 接收参数locale,该参数传递国际化环境,例如zh_CN.
        String localeinfo = request.getParameter("locale");
        // 创建ResourceBundle对象
        ResourceBundle bundle = null;
        // 判断国际化环境内容是否为空
        if(localeinfo == null){
            // 如果为空,使用默认的国际化资源文件内容.
            bundle = ResourceBundle.getBundle("info");// 使用默认
        }else{
            // 如果不为空,将国际化环境参数,拆分成语言和国家.
            String[] arr = localeinfo.split("_");
            if(arr.length>1){
                // 表示国际化环境参数包含语言和国家内容
                bundle = ResourceBundle.getBundle("info",new Locale(arr[0],arr[1]));
            }else if(arr.length == 1){
                // 表示国际化环境参数只包含语言内容
                bundle = ResourceBundle.getBundle("info",new Locale(arr[0]));
            }
        }
    %>
    <h1><%=bundle.getString("info") %></h1>
    <form action="#" method="post">
        <%=bundle.getString("username") %> <input type="text" name="username" /><br/>
        <%=bundle.getString("password") %> <input type="password" name="password" /><br/>
        <input type="submit" value="<%=bundle.getString("submit") %>" />
    </form>
  </body>
</html>

[复制代码](javascript:void(0)😉

4.7. JSTL国际化标签

上述登录案例除了使用在JSP页面嵌入Java代码实现以外,还可以通过JSTL标签库的I18N标签库来实现。具体实现方式如下:

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>login.jsp</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
    <!-- 设置指定国家locale -->
    <fmt:setLocale value="${param.locale}"/>
    <!-- 创建ResourceBundle -->
    <!-- 将ResourceBundle对象保存 page范围 bundle 属性中 -->
    <fmt:setBundle basename="info" var="bundle" scope="page"/>
    <!-- 显示form表单 -->
    <h1><fmt:message bundle="${bundle}" key="info" /> </h1>
    <form action="xxxx" method="post">
        <fmt:message bundle="${bundle}" key="username" />  <input type="text" name="username" /><br/>
        <fmt:message bundle="${bundle}" key="password" />  <input type="password" name="password" /><br/>
        <input type="submit" value="<fmt:message bundle="${bundle}" key="submit" /> " />
    </form>
  </body>
</html>

[复制代码](javascript:void(0)😉

JSTL标签库的I18N标签库除了以上标签外,也提供了日期和数字的格式化功能。具体内容参考如下内容:

[复制代码](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>fmt.jsp</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
    <%
        pageContext.setAttribute("date", new Date());
        pageContext.setAttribute("num", "3");
    %>
    <fmt:formatDate value="${date }" pattern="yyyy-MM-dd HH:mm:ss"/><br/>
    <fmt:formatNumber value="${num }" pattern="#.##" /><br/>
    <fmt:formatNumber value="${num }" pattern="0.00" /><br/>
  </body>
</html>

[复制代码](javascript:void(0)😉

}" key=“username” />

<fmt:message bundle=" b u n d l e " k e y = " p a s s w o r d " / > < i n p u t t y p e = " p a s s w o r d " n a m e = " p a s s w o r d " / > < b r / > < i n p u t t y p e = " s u b m i t " v a l u e = " < f m t : m e s s a g e b u n d l e = " {bundle}" key="password" /> <input type="password" name="password" /><br/> <input type="submit" value="<fmt:message bundle=" bundle"key="password"/><inputtype="password"name="password"/><br/><inputtype="submit"value="<fmt:messagebundle="{bundle}" key=“submit” /> " />

```

[[外链图片转存中…(img-FcGU60Y7-1644731558925)]](javascript:void(0)😉

JSTL标签库的I18N标签库除了以上标签外,也提供了日期和数字的格式化功能。具体内容参考如下内容:

[[外链图片转存中…(img-Gr8vdXFt-1644731558925)]](javascript:void(0)😉

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>fmt.jsp</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>
  <body>
    <%
        pageContext.setAttribute("date", new Date());
        pageContext.setAttribute("num", "3");
    %>
    <fmt:formatDate value="${date }" pattern="yyyy-MM-dd HH:mm:ss"/><br/>
    <fmt:formatNumber value="${num }" pattern="#.##" /><br/>
    <fmt:formatNumber value="${num }" pattern="0.00" /><br/>
  </body>
</html>

[[外链图片转存中…(img-Pu8HGRkC-1644731558925)]](javascript:void(0)😉

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值