JSP 快速指南



JSP - 概述

什么是 JavaServer Pages?

JavaServer Pages (JSP) 是一种用于开发支持动态内容的网页的技术。这有助于开发人员通过使用特殊的 JSP 标签(大多数以 <% 开头,以 %> 结尾)在 HTML 页面中插入 Java 代码。

JavaServer Pages 组件是一种类型的 Java servlet,旨在充当 Java Web 应用程序的用户界面。Web 开发人员将 JSP 编写为文本文件,这些文件结合了 HTML 或 XHTML 代码、XML 元素以及嵌入的 JSP 动作和命令。

使用 JSP,您可以通过网页表单收集用户输入,显示来自数据库或其他来源的记录,以及动态创建网页。

JSP 标签可用于各种目的,例如从数据库检索信息或注册用户偏好、访问 JavaBeans 组件、在页面之间传递控制以及在请求、页面等之间共享信息。

为什么要使用 JSP?

JavaServer Pages 通常与使用 **通用网关接口 (CGI)** 实现的程序具有相同的用途。但与 CGI 相比,JSP 提供了几个优势。

  • 性能显着提高,因为 JSP 允许在 HTML 页面本身嵌入动态元素,而不是拥有单独的 CGI 文件。

  • JSP 始终在服务器处理之前进行编译,而 CGI/Perl 则需要服务器每次请求页面时加载解释器和目标脚本。

  • JavaServer Pages 建立在 Java Servlet API 之上,因此与 Servlet 一样,JSP 也能够访问所有强大的企业级 Java API,包括 **JDBC、JNDI、EJB、JAXP** 等。

  • JSP 页面可以与处理业务逻辑的 servlet 结合使用,这是 Java servlet 模板引擎支持的模型。

最后,JSP 是 Java EE 的一部分,Java EE 是一个完整的企业级应用程序平台。这意味着 JSP 可以参与最简单的应用程序到最复杂和最苛刻的应用程序。

JSP 的优点

下表列出了使用 JSP 相比其他技术的其他优势:

与 Active Server Pages (ASP) 相比

JSP 的优势有两方面。首先,动态部分是用 Java 编写的,而不是 Visual Basic 或其他 MS 特定的语言,因此它更强大且更易于使用。其次,它可以移植到其他操作系统和非 Microsoft Web 服务器。

与纯 Servlet 相比

编写(和修改!)常规 HTML 比编写大量生成 HTML 的 println 语句更方便。

与服务器端包含 (SSI) 相比

SSI 实际上仅用于简单的包含,不适用于使用表单数据、建立数据库连接等“真实”程序。

与 JavaScript 相比

JavaScript 可以在客户端动态生成 HTML,但几乎无法与 Web 服务器交互以执行诸如数据库访问和图像处理等复杂任务。

与静态 HTML 相比

当然,常规 HTML 不能包含动态信息。

接下来是什么?

我将逐步指导您设置环境以开始使用 JSP。我假设您对 Java 编程有很好的实践经验,以便继续学习 JSP。

如果您不了解 Java 编程语言,那么我们建议您浏览我们的 Java 教程 以了解 Java 编程。

JSP - 环境搭建

开发环境是您开发 JSP 程序、测试它们并最终运行它们的地方。

本教程将指导您设置 JSP 开发环境,这包括以下步骤:

设置 Java 开发工具包

此步骤涉及下载 Java 软件开发工具包 (SDK) 的实现并适当地设置 PATH 环境变量。

您可以从 Oracle 的 Java 网站下载 SDK:Java SE 下载

下载 Java 实现后,请按照给定的说明安装和配置设置。最后,设置 **PATH 和 JAVA_HOME** 环境变量以引用包含 **java** 和 **javac** 的目录,通常分别为 **java_install_dir/bin** 和 **java_install_dir**。

如果您运行的是 Windows 并将 SDK 安装在 **C:\jdk1.5.0_20** 中,则需要在 **C:\autoexec.bat** 文件中添加以下行。

set PATH = C:\jdk1.5.0_20\bin;%PATH%
set JAVA_HOME = C:\jdk1.5.0_20

或者,在 **Windows NT/2000/XP** 上,您也可以右键单击 **我的电脑**,选择 **属性**,然后选择 **高级**,然后选择 **环境变量**。然后,您将更新 PATH 值并按确定按钮。

在 Unix(Solaris、Linux 等)上,如果 SDK 安装在 **/usr/local/jdk1.5.0_20** 中并且您使用的是 C shell,则您将在 **.cshrc** 文件中放入以下内容。

setenv PATH /usr/local/jdk1.5.0_20/bin:$PATH
setenv JAVA_HOME /usr/local/jdk1.5.0_20

或者,如果您使用 **集成开发环境 (IDE)**(如 **Borland JBuilder、Eclipse、IntelliJ IDEA** 或 **Sun ONE Studio**),请编译并运行一个简单的程序以确认 IDE 知道您安装 Java 的位置。

设置 Web 服务器:Tomcat

市场上提供许多支持 JavaServer Pages 和 Servlet 开发的 Web 服务器。一些 Web 服务器可以免费下载,Tomcat 就是其中之一。

Apache Tomcat 是 JavaServer Pages 和 Servlet 技术的开源软件实现,可以充当测试 JSP 和 Servlet 的独立服务器,并且可以与 Apache Web 服务器集成。以下是您在机器上设置 Tomcat 的步骤:

  • https://tomcat.net.cn/ 下载最新版本的 Tomcat。

  • 下载安装程序后,将二进制分发版解压缩到一个方便的位置。例如,在 Windows 上的 **C:\apache-tomcat-5.5.29** 中,或在 Linux/Unix 上的 **/usr/local/apache-tomcat-5.5.29** 中,并创建指向这些位置的 **CATALINA_HOME** 环境变量。

可以通过在 Windows 机器上执行以下命令来启动 Tomcat:

%CATALINA_HOME%\bin\startup.bat
 
or
 
C:\apache-tomcat-5.5.29\bin\startup.bat

可以通过在 Unix(Solaris、Linux 等)机器上执行以下命令来启动 Tomcat:

$CATALINA_HOME/bin/startup.sh
 
or
 
/usr/local/apache-tomcat-5.5.29/bin/startup.sh

成功启动后,可以通过访问 **https://127.0.0.1:8080/** 来使用 Tomcat 附带的默认 Web 应用程序。

执行后,您将收到以下输出:

Tomcat Home page

有关配置和运行 Tomcat 的更多信息,请参阅此处包含的文档,以及 Tomcat 网站:https://tomcat.net.cn/

可以通过在 Windows 机器上执行以下命令来停止 Tomcat:

%CATALINA_HOME%\bin\shutdown
or

C:\apache-tomcat-5.5.29\bin\shutdown

可以通过在 Unix(Solaris、Linux 等)机器上执行以下命令来停止 Tomcat:

$CATALINA_HOME/bin/shutdown.sh

or

/usr/local/apache-tomcat-5.5.29/bin/shutdown.sh

设置 CLASSPATH

由于 servlet 不是 Java Platform Standard Edition 的一部分,因此您必须将 servlet 类识别给编译器。

如果您运行的是 Windows,则需要在 **C:\autoexec.bat** 文件中添加以下行。

set CATALINA = C:\apache-tomcat-5.5.29
set CLASSPATH = %CATALINA%\common\lib\jsp-api.jar;%CLASSPATH%

或者,在 **Windows NT/2000/XP** 上,您也可以右键单击 **我的电脑**,选择 **属性**,然后选择 **高级**,然后选择 **环境变量**。然后,您将更新 CLASSPATH 值并按确定按钮。

在 Unix(Solaris、Linux 等)上,如果您使用的是 C shell,则您将在 **.cshrc** 文件中添加以下行。

setenv CATALINA = /usr/local/apache-tomcat-5.5.29
setenv CLASSPATH $CATALINA/common/lib/jsp-api.jar:$CLASSPATH

**注意** - 假设您的开发目录是 **C:\JSPDev (Windows)** 或 **/usr/JSPDev (Unix)**,那么您也需要将这些目录添加到 CLASSPATH 中。

JSP - 架构

Web 服务器需要一个 JSP 引擎,即一个容器来处理 JSP 页面。JSP 容器负责拦截对 JSP 页面的请求。本教程使用 Apache,它具有内置的 JSP 容器来支持 JSP 页面的开发。

JSP 容器与 Web 服务器一起工作,为 JSP 提供运行时环境和其他服务。它知道如何理解 JSP 中包含的特殊元素。

下图显示了 JSP 容器和 JSP 文件在 Web 应用程序中的位置。

JSP Architecture

JSP 处理

以下步骤说明了 Web 服务器如何使用 JSP 创建网页:

  • 与普通页面一样,您的浏览器会向 Web 服务器发送 HTTP 请求。

  • Web 服务器识别出 HTTP 请求是针对 JSP 页面的,并将其转发到 JSP 引擎。这是通过使用 URL 或 JSP 页面完成的,该页面以 **.jsp** 而不是 **.html** 结尾。

  • JSP 引擎从磁盘加载 JSP 页面并将其转换为 servlet 内容。这种转换非常简单,其中所有模板文本都转换为 println( ) 语句,所有 JSP 元素都转换为 Java 代码。此代码实现了页面的相应动态行为。

  • JSP 引擎将 servlet 编译为可执行类,并将原始请求转发到 servlet 引擎。

  • Web服务器的一部分,称为Servlet引擎,加载Servlet类并执行它。在执行过程中,Servlet以HTML格式生成输出。Servlet引擎在HTTP响应中将输出进一步传递给Web服务器。

  • Web服务器将HTTP响应转发到您的浏览器,将其视为静态HTML内容。

  • 最后,Web浏览器处理HTTP响应中动态生成的HTML页面,就像处理静态页面一样。

所有上述步骤都可以在下图中看到:

JSP Processing

通常,JSP引擎会检查JSP文件对应的Servlet是否存在,以及JSP文件的修改日期是否早于Servlet。如果JSP文件早于其生成的Servlet,则JSP容器假定JSP文件没有更改,并且生成的Servlet仍然与JSP文件的内容匹配。这使得该过程比其他脚本语言(如PHP)更有效率,因此速度更快。

因此,从某种意义上说,JSP页面实际上只是编写Servlet的另一种方式,无需成为Java编程高手。除了转换阶段外,JSP页面的处理方式与普通Servlet完全相同。

JSP - 生命周期

在本章中,我们将讨论JSP的生命周期。理解JSP底层功能的关键是了解它们遵循的简单生命周期。

JSP生命周期定义为从创建到销毁的过程。这类似于Servlet生命周期,但增加了一个步骤,即需要将JSP编译成Servlet。

JSP遵循的路径

以下是JSP遵循的路径:

  • 编译
  • 初始化
  • 执行
  • 清理

JSP生命周期的四个主要阶段与Servlet生命周期非常相似。下面描述了这四个阶段:

JSP Life Cycle

JSP编译

当浏览器请求JSP时,JSP引擎首先检查是否需要编译页面。如果页面从未被编译过,或者自上次编译以来JSP文件已被修改,则JSP引擎会编译该页面。

编译过程包括三个步骤:

  • 解析JSP。
  • 将JSP转换为Servlet。
  • 编译Servlet。

JSP初始化

当容器加载JSP时,它会在服务任何请求之前调用jspInit()方法。如果您需要执行特定于JSP的初始化,请覆盖jspInit()方法:

public void jspInit(){
   // Initialization code...
}

通常,初始化仅执行一次,并且与servlet的init方法一样,您通常在jspInit方法中初始化数据库连接、打开文件和创建查找表。

JSP执行

JSP生命周期的这一阶段表示与请求的所有交互,直到JSP被销毁。

每当浏览器请求JSP并且页面已被加载和初始化时,JSP引擎都会调用JSP中的_jspService()方法。

_jspService()方法以HttpServletRequestHttpServletResponse作为其参数,如下所示:

void _jspService(HttpServletRequest request, HttpServletResponse response) {
   // Service handling code...
}

JSP的_jspService()方法是根据请求调用的。它负责为该请求生成响应,并且该方法还负责为所有七种HTTP方法生成响应,即GET、POST、DELETE等。

JSP清理

JSP生命周期的销毁阶段表示容器正在将JSP从使用中移除。

jspDestroy()方法是Servlet的destroy方法在JSP中的等效方法。当您需要执行任何清理操作(例如释放数据库连接或关闭打开的文件)时,请覆盖jspDestroy。

jspDestroy()方法具有以下形式:

public void jspDestroy() {
   // Your cleanup code goes here.
}

JSP - 语法

在本章中,我们将讨论JSP中的语法。我们将了解与JSP开发相关的简单语法(即元素)的基本用法。

JSP元素

下面描述了JSP元素:

脚本片段

脚本片段可以包含任意数量的JAVA语言语句、变量或方法声明,或在页面脚本语言中有效的表达式。

以下是脚本片段的语法:

<% code fragment %>

您可以将上述语法的XML等效形式写成如下:

<jsp:scriptlet>
   code fragment
</jsp:scriptlet>

您编写的任何文本、HTML标签或JSP元素都必须位于脚本片段之外。以下是JSP的简单且第一个示例:

<html>
   <head><title>Hello World</title></head>
   
   <body>
      Hello World!<br/>
      <%
         out.println("Your IP address is " + request.getRemoteAddr());
      %>
   </body>
</html>

注意 - 假设Apache Tomcat安装在C:\apache-tomcat-7.0.2中,并且您的环境已根据环境设置教程进行设置。

让我们将上述代码保存在名为hello.jsp的JSP文件中,并将此文件放在C:\apache-tomcat7.0.2\webapps\ROOT目录中。使用URLhttps://127.0.0.1:8080/hello.jsp浏览它。上述代码将生成以下结果:

Hello World

JSP声明

声明声明一个或多个变量或方法,您可以在JSP文件后面的Java代码中使用这些变量或方法。您必须在JSP文件中使用变量或方法之前声明它。

以下是JSP声明的语法:

<%! declaration; [ declaration; ]+ ... %>

您可以将上述语法的XML等效形式写成如下:

<jsp:declaration>
   code fragment
</jsp:declaration>

以下是JSP声明的示例:

<%! int i = 0; %> 
<%! int a, b, c; %> 
<%! Circle a = new Circle(2.0); %> 

JSP表达式

JSP表达式元素包含一个被求值的脚本语言表达式,该表达式被转换为字符串,并插入到JSP文件中表达式出现的位置。

因为表达式的值被转换为字符串,所以您可以在文本行中使用表达式,无论它是否用HTML标记,都在JSP文件中。

表达式元素可以包含任何根据Java语言规范有效的表达式,但您不能使用分号来结束表达式。

以下是JSP表达式的语法:

<%= expression %>

您可以将上述语法的XML等效形式写成如下:

<jsp:expression>
   expression
</jsp:expression>

以下示例显示了一个JSP表达式:

<html> 
   <head><title>A Comment Test</title></head> 
   
   <body>
      <p>Today's date: <%= (new java.util.Date()).toLocaleString()%></p>
   </body> 
</html> 

上述代码将生成以下结果:

Today's date: 11-Sep-2010 21:24:25

JSP注释

JSP注释标记JSP容器应忽略的文本或语句。当您想要隐藏或“注释掉”JSP页面的一部分时,JSP注释很有用。

以下是JSP注释的语法:

<%-- This is JSP comment --%>

以下示例显示了JSP注释:

<html> 
   <head><title>A Comment Test</title></head> 
   
   <body> 
      <h2>A Test of Comments</h2> 
      <%-- This comment will not be visible in the page source --%> 
   </body> 
</html> 

上述代码将生成以下结果:

A Test of Comments

在各种情况下,您可以使用少量特殊的构造来插入注释或字符,否则这些注释或字符将被特殊处理。以下是摘要:

序号 语法和用途
1

<%-- comment --%>

JSP注释。被JSP引擎忽略。

2

<!-- comment -->

HTML注释。被浏览器忽略。

3

<\%

表示静态<%字面量。

4

%\>

表示静态%>字面量。

5

\'

使用单引号的属性中的单引号。

6

\"

使用双引号的属性中的双引号。

JSP指令

JSP指令影响Servlet类的整体结构。它通常具有以下形式:

<%@ directive attribute="value" %>

指令标签有三种类型:

序号 指令和说明
1

<%@ page ... %>

定义页面相关的属性,例如脚本语言、错误页面和缓冲要求。

2

<%@ include ... %>

在转换阶段包含文件。

3

<%@ taglib ... %>

声明一个标签库,其中包含在页面中使用的自定义操作

我们将在单独的章节JSP - 指令中解释JSP指令

JSP操作

JSP操作使用XML语法中的构造来控制Servlet引擎的行为。您可以动态插入文件、重用JavaBeans组件、将用户转发到另一个页面或为Java插件生成HTML。

操作元素只有一个语法,因为它符合XML标准:

<jsp:action_name attribute="value" />

操作元素基本上是预定义的函数。下表列出了可用的JSP操作:

序号 语法和用途
1

jsp:include

在请求页面时包含文件。

2

jsp:useBean

查找或实例化JavaBean。

3

jsp:setProperty

设置JavaBean的属性。

4

jsp:getProperty

将JavaBean的属性插入输出中。

5

jsp:forward

将请求者转发到新页面。

6

jsp:plugin

生成特定于浏览器的代码,为Java插件创建OBJECT或EMBED标签。

7

jsp:element

动态定义XML元素。

8

jsp:attribute

定义动态定义的XML元素的属性。

9

jsp:body

定义动态定义的XML元素的主体。

10

jsp:text

用于在JSP页面和文档中编写模板文本。

我们将在单独的章节JSP - 操作中解释JSP操作

JSP隐式对象

JSP支持九个自动定义的变量,也称为隐式对象。这些变量是:

序号 对象和说明
1

request

这是与请求关联的HttpServletRequest对象。

2

response

这是与对客户端的响应关联的HttpServletResponse对象。

3

out

这是用于向客户端发送输出的PrintWriter对象。

4

session

这是与请求关联的HttpSession对象。

5

application

这是与应用程序上下文关联的ServletContext对象。

6

config

这是与页面关联的ServletConfig对象。

7

pageContext

它封装了服务器特定功能的使用,例如更高性能的JspWriters

8

page

这仅仅是this的同义词,用于调用翻译后的Servlet类定义的方法。

9

Exception

Exception对象允许通过指定的JSP访问异常数据。

我们将在单独的章节JSP - 隐式对象中解释JSP隐式对象。

控制流语句

您可以在JSP编程中使用Java的所有API和构建块,包括决策语句、循环等。

决策语句

if...else块的开头像一个普通的脚本片段,但在每一行结束时都会关闭脚本片段,并在脚本片段标签之间包含HTML文本。

<%! int day = 3; %> 
<html> 
   <head><title>IF...ELSE Example</title></head> 
   
   <body>
      <% if (day == 1 || day == 7) { %>
         <p> Today is weekend</p>
      <% } else { %>
         <p> Today is not weekend</p>
      <% } %>
   </body> 
</html> 

上述代码将生成以下结果:

Today is not weekend

现在看一下以下switch...case块,它使用out.println()并在脚本片段内以稍微不同的方式编写:

<%! int day = 3; %> 
<html> 
   <head><title>SWITCH...CASE Example</title></head> 
   
   <body>
      <% 
         switch(day) {
            case 0:
               out.println("It\'s Sunday.");
               break;
            case 1:
               out.println("It\'s Monday.");
               break;
            case 2:
               out.println("It\'s Tuesday.");
               break;
            case 3:
               out.println("It\'s Wednesday.");
               break;
            case 4:
               out.println("It\'s Thursday.");
               break;
            case 5:
               out.println("It\'s Friday.");
               break;
            default:
               out.println("It's Saturday.");
         }
      %>
   </body> 
</html> 

上述代码将生成以下结果:

It's Wednesday.

循环语句

您还可以使用Java中的三种基本类型的循环块:for、while和do…while块在您的JSP编程中。

让我们看一下以下for循环示例:

<%! int fontSize; %> 
<html> 
   <head><title>FOR LOOP Example</title></head> 
   
   <body>
      <%for ( fontSize = 1; fontSize <= 3; fontSize++){ %>
         <font color = "green" size = "<%= fontSize %>">
            JSP Tutorial
      </font><br />
      <%}%>
   </body> 
</html> 

上述代码将生成以下结果:


   JSP Tutorial

JSP Tutorial
JSP Tutorial

上述示例可以使用while循环写成如下:

<%! int fontSize; %> 
<html> 
   <head><title>WHILE LOOP Example</title></head> 
   
   <body>
      <%while ( fontSize <= 3){ %>
         <font color = "green" size = "<%= fontSize %>">
            JSP Tutorial
         </font><br />
         <%fontSize++;%>
      <%}%>
   </body> 
</html> 

上述代码将生成以下结果:


   JSP Tutorial



   JSP Tutorial



   JSP Tutorial

JSP运算符

JSP支持Java支持的所有逻辑和算术运算符。下表列出了所有运算符,其中优先级最高的出现在表顶部,优先级最低的出现在底部。

在一个表达式中,优先级较高的运算符将首先被求值。

类别 运算符 结合性
后缀 () [] . (点运算符) 从左到右
一元 ++ - - ! ~ 从右到左
乘法 * / % 从左到右
加法 + - 从左到右
移位 >> >>> << 从左到右
关系 > >= < <= 从左到右
相等 == != 从左到右
按位与 & 从左到右
按位异或 ^ 从左到右
按位或 | 从左到右
逻辑与 && 从左到右
逻辑或 || 从左到右
条件 ?: 从右到左
赋值 = += -= *= /= %= >>= <<= &= ^= |= 从右到左
逗号 , 从左到右

JSP字面量

JSP表达式语言定义了以下字面量:

  • 布尔型 - true 和 false

  • 整数 - 与Java相同

  • 浮点数 - 与Java相同

  • 字符串 - 使用单引号和双引号;" 被转义为 \", ' 被转义为 \', \ 被转义为 \\。

  • - null

JSP - 指令

在本章中,我们将讨论JSP中的指令。这些指令为容器提供方向和说明,告诉它如何处理JSP处理的某些方面。

JSP指令影响Servlet类的整体结构。它通常具有以下形式:

<%@ directive attribute = "value" %>

指令可以具有许多属性,您可以将这些属性列为键值对,并用逗号分隔。

@符号和指令名称之间以及最后一个属性和结束%>之间的空格是可选的。

指令标签有三种类型:

序号 指令和说明
1

<%@ page ... %>

定义页面相关的属性,例如脚本语言、错误页面和缓冲要求。

2

<%@ include ... %>

在转换阶段包含文件。

3

<%@ taglib ... %>

声明一个标签库,其中包含在页面中使用的自定义操作

JSP - page指令

page 指令用于向容器提供指令。这些指令与当前 JSP 页面相关。您可以在 JSP 页面的任何位置编写 page 指令。按照惯例,page 指令写在 JSP 页面的顶部。

以下是 page 指令的基本语法:

<%@ page attribute = "value" %>

您可以将上述语法的XML等效形式写成如下:

<jsp:directive.page attribute = "value" />

属性

下表列出了与 page 指令关联的属性:

序号 属性 & 用途
1

buffer

指定输出流的缓冲模型。

2

autoFlush

控制 servlet 输出缓冲的行为。

3

contentType

定义字符编码方案。

4

errorPage

定义另一个 JSP 的 URL,该 JSP 报告 Java 未经检查的运行时异常。

5

isErrorPage

指示此 JSP 页面是否为另一个 JSP 页面的 errorPage 属性指定的 URL。

6

extends

指定生成的 servlet 必须扩展的超类。

7

import

指定 JSP 中使用的包或类的列表,就像 Java import 语句对 Java 类所做的那样。

8

info

定义一个字符串,可以通过 servlet 的 getServletInfo() 方法访问。

9

isThreadSafe

定义生成的 servlet 的线程模型。

10

language

定义 JSP 页面中使用的编程语言。

11

session

指定 JSP 页面是否参与 HTTP 会话

12

isELIgnored

指定是否忽略 JSP 页面中的 EL 表达式。

13

isScriptingEnabled

确定是否允许使用脚本元素。

有关所有上述属性的更多详细信息,请查看 Page 指令

include 指令

include 指令用于在翻译阶段包含文件。此指令告诉容器在翻译阶段将其他外部文件的内容与当前 JSP 合并。您可以在 JSP 页面的任何位置编写 include 指令。

此指令的一般使用形式如下:

<%@ include file = "relative url" >

include 指令中的文件名实际上是相对 URL。如果您只指定一个文件名而不带关联路径,则 JSP 编译器会假定该文件与您的 JSP 位于同一目录中。

您可以将上述语法的XML等效形式写成如下:

<jsp:directive.include file = "relative url" />

有关 include 指令的更多详细信息,请查看 Include 指令

taglib 指令

JavaServer Pages API 允许您定义自定义 JSP 标记,这些标记看起来像 HTML 或 XML 标记,而标记库是一组实现自定义行为的用户定义标记。

taglib 指令声明您的 JSP 页面使用一组自定义标记,标识库的位置,并提供识别 JSP 页面中自定义标记的方法。

taglib 指令遵循以下语法:

<%@ taglib uri="uri" prefix = "prefixOfTag" >

这里,uri 属性值解析为容器理解的位置,prefix 属性通知容器哪些标记是自定义操作。

您可以将上述语法的XML等效形式写成如下:

<jsp:directive.taglib uri = "uri" prefix = "prefixOfTag" />

有关 taglib 指令的更多详细信息,请查看 Taglib 指令

JSP - 动作

在本章中,我们将讨论 JSP 中的动作。这些动作使用 XML 语法中的构造来控制 servlet 引擎的行为。您可以动态插入文件、重用 JavaBeans 组件、将用户转发到另一个页面或为 Java 插件生成 HTML。

操作元素只有一个语法,因为它符合XML标准:

<jsp:action_name attribute = "value" />

动作元素基本上是预定义的函数。下表列出了可用的 JSP 动作:

序号 语法和用途
1

jsp:include

在请求页面时包含文件。

2

jsp:useBean

查找或实例化JavaBean。

3

jsp:setProperty

设置JavaBean的属性。

4

jsp:getProperty

将JavaBean的属性插入输出中。

5

jsp:forward

将请求者转发到新页面。

6

jsp:plugin

生成特定于浏览器的代码,为Java插件创建OBJECT或EMBED标签。

7

jsp:element

动态定义XML元素。

8

jsp:attribute

定义动态定义的XML元素的属性。

9

jsp:body

定义动态定义的XML元素的主体。

10

jsp:text

用于在JSP页面和文档中编写模板文本。

常用属性

所有动作元素都有两个共同属性:id 属性和 scope 属性。

Id 属性

id 属性唯一标识动作元素,并允许在 JSP 页面内部引用该动作。如果动作创建了一个对象的实例,则可以使用 id 值通过隐式对象 PageContext 来引用它。

Scope 属性

此属性标识动作元素的生命周期。id 属性和 scope 属性直接相关,因为 scope 属性决定了与 id 关联的对象的生命周期。scope 属性有四个可能的值:(a) page,(b) request,(c) session(d) application

<jsp:include> 动作

此动作允许您将文件插入正在生成的页面中。语法如下:

<jsp:include page = "relative URL" flush = "true" />

include 指令不同,后者在 JSP 页面被翻译成 servlet 时插入文件,此动作在请求页面时插入文件。

下表列出了与 include 动作关联的属性:

序号 属性 & 描述
1

page

要包含的页面的相对 URL。

2

flush

布尔属性确定在包含包含资源之前是否将其缓冲区刷新。

示例

让我们定义以下两个文件 (a) date.jsp(b) main.jsp 如下:

以下是 date.jsp 文件的内容:

<p>Today's date: <%= (new java.util.Date()).toLocaleString()%></p>

以下是 main.jsp 文件的内容:

<html>
   <head>
      <title>The include Action Example</title>
   </head>
   
   <body>
      <center>
         <h2>The include action Example</h2>
         <jsp:include page = "date.jsp" flush = "true" />
      </center>
   </body>
</html>

现在让我们将所有这些文件保存在根目录中,并尝试访问 main.jsp。您将收到以下输出:

The include action Example

Today's date: 12-Sep-2010 14:54:22

<jsp:useBean> 动作

useBean 动作非常通用。它首先使用 id 和 scope 变量搜索现有对象。如果未找到对象,则尝试创建指定的对象。

加载 bean 的最简单方法如下:

<jsp:useBean id = "name" class = "package.class" />

加载 bean 类后,您可以使用 jsp:setPropertyjsp:getProperty 动作修改和检索 bean 属性。

下表列出了与 useBean 动作关联的属性:

序号 属性 & 描述
1

class

指定 bean 的完整包名称。

2

type

指定将引用对象的变量的类型。

3

beanName

给出由 java.beans.Beans 类的 instantiate() 方法指定的 bean 的名称。

在提供与这些动作相关的有效示例之前,让我们先讨论 jsp:setPropertyjsp:getProperty 动作。

<jsp:setProperty> 动作

setProperty 动作设置 Bean 的属性。在执行此动作之前必须先定义 Bean。有两种基本方法可以使用 setProperty 动作:

您可以如下所示在 jsp:useBean 元素之后但在其外部使用 jsp:setProperty

<jsp:useBean id = "myName" ... />
...
<jsp:setProperty name = "myName" property = "someProperty" .../>

在这种情况下,无论是否实例化了新的 bean 或找到了现有的 bean,都会执行 jsp:setProperty

jsp:setProperty 可以出现的第二个上下文是在 jsp:useBean 元素的主体内部,如下所示:

<jsp:useBean id = "myName" ... >
   ...
   <jsp:setProperty name = "myName" property = "someProperty" .../>
</jsp:useBean>

这里,只有在实例化了一个新对象时才会执行 jsp:setProperty,而不是在找到一个现有对象时。

下表列出了与 setProperty 动作关联的属性:

序号 属性 & 描述
1

name

指定将设置其属性的 bean。必须事先定义 Bean。

2

property

指示要设置的属性。值“*”表示所有名称与 bean 属性名称匹配的请求参数都将传递到相应的 setter 方法。

3

value

要分配给给定属性的值。如果参数的值为 null 或参数不存在,则忽略 setProperty 动作。

4

param

param 属性是要接收属性值的请求参数的名称。您不能同时使用 value 和 param,但允许两者都不使用。

<jsp:getProperty> 动作

getProperty 动作用于检索给定属性的值并将其转换为字符串,最后将其插入输出中。

getProperty 动作只有两个属性,这两个属性都是必需的。getProperty 动作的语法如下:

<jsp:useBean id = "myName" ... />
...
<jsp:getProperty name = "myName" property = "someProperty" .../>

下表列出了与 getProperty 动作关联的必需属性:

序号 属性 & 描述
1

name

具有要检索的属性的 Bean 的名称。必须事先定义 Bean。

2

property

property 属性是要检索的 Bean 属性的名称。

示例

让我们定义一个测试 bean,该 bean 将在我们的示例中进一步使用:

/* File: TestBean.java */
package action;
 
public class TestBean {
   private String message = "No message specified";
 
   public String getMessage() {
      return(message);
   }
   public void setMessage(String message) {
      this.message = message;
   }
}

将上述代码编译到生成的 TestBean.class 文件中,并确保您将 TestBean.class 复制到 C:\apache-tomcat-7.0.2\webapps\WEB-INF\classes\action 文件夹中,并且 CLASSPATH 变量也应设置为该文件夹:

现在在 main.jsp 文件中使用以下代码。这将加载 bean 并设置/获取一个简单的字符串参数:

<html>
   
   <head>
      <title>Using JavaBeans in JSP</title>
   </head>
   
   <body>
      <center>
         <h2>Using JavaBeans in JSP</h2>
         <jsp:useBean id = "test" class = "action.TestBean" />
         <jsp:setProperty name = "test"  property = "message" 
            value = "Hello JSP..." />
            
         <p>Got message....</p>
         <jsp:getProperty name = "test" property = "message" />
      </center>
   </body>
</html>

现在让我们尝试访问 main.jsp,它将显示以下结果:

Using JavaBeans in JSP

Got message.... Hello JSP...

<jsp:forward> 动作

forward 动作终止当前页面的操作并将请求转发到另一个资源,例如静态页面、另一个 JSP 页面或 Java Servlet。

以下是 forward 动作的语法:

<jsp:forward page = "Relative URL" />

下表列出了与 forward 动作关联的必需属性:

序号 属性 & 描述
1

page

应包含另一个资源的相对 URL,例如静态页面、另一个 JSP 页面或 Java Servlet。

示例

让我们重用以下两个文件 (a) date.jsp(b) main.jsp 如下:

以下是 date.jsp 文件的内容:

<p>Today's date: <%= (new java.util.Date()).toLocaleString()%></p>

以下是 main.jsp 文件的内容:

<html>
   <head>
      <title>The include Action Example</title>
   </head>
   
   <body>
      <center>
         <h2>The include action Example</h2>
         <jsp:forward page = "date.jsp" />
      </center>
   </body>
</html>

现在让我们将所有这些文件保存在根目录中,并尝试访问 main.jsp。这将显示如下所示的结果。

这里它丢弃了主页面中的内容,只显示了从转发页面中获取的内容。

Today's date: 12-Sep-2010 14:54:22

<jsp:plugin> 动作

plugin 动作用于将 Java 组件插入 JSP 页面。它确定浏览器的类型并根据需要插入 <object><embed> 标记。

如果所需的插件不存在,它将下载插件,然后执行 Java 组件。Java 组件可以是 Applet 或 JavaBean。

plugin 动作有几个属性,对应于用于格式化 Java 组件的常用 HTML 标记。<param> 元素也可用于向 Applet 或 Bean 发送参数。

以下是使用 plugin 动作的典型语法:

<jsp:plugin type = "applet" codebase = "dirname" code = "MyApplet.class"
   width = "60" height = "80">
   <jsp:param name = "fontcolor" value = "red" />
   <jsp:param name = "background" value = "black" />
 
   <jsp:fallback>
      Unable to initialize Java Plugin
   </jsp:fallback>
 
</jsp:plugin>

如果您有兴趣,可以使用一些 applet 来尝试此操作。一个新的元素,<fallback> 元素,可以用来指定一个错误字符串,在组件失败的情况下发送给用户。

The <jsp:element> Action

The <jsp:attribute> Action

The <jsp:body> Action

<jsp:element>,<jsp:attribute><jsp:body> 动作用于动态定义 XML 元素。动态这个词很重要,因为它意味着 XML 元素可以在请求时生成,而不是在编译时静态生成。

以下是一个动态定义 XML 元素的简单示例:

<%@page language = "java" contentType = "text/html"%>
<html xmlns = "http://www.w3c.org/1999/xhtml"
   xmlns:jsp = "http://java.sun.com/JSP/Page">
   
   <head><title>Generate XML Element</title></head>
   
   <body>
      <jsp:element name = "xmlElement">
         <jsp:attribute name = "xmlElementAttr">
            Value for the attribute
         </jsp:attribute>
         
         <jsp:body>
            Body for XML element
         </jsp:body>
      
      </jsp:element>
   </body>
</html>

这将在运行时生成以下 HTML 代码:

<html xmlns = "http://www.w3c.org/1999/xhtml" xmlns:jsp = "http://java.sun.com/JSP/Page">
   <head><title>Generate XML Element</title></head>
   
   <body>
      <xmlElement xmlElementAttr = "Value for the attribute">
         Body for XML element
      </xmlElement>
   </body>
</html>

<jsp:text> 动作

<jsp:text> 动作可用于在 JSP 页面和文档中编写模板文本。以下是此操作的简单语法:

<jsp:text>Template data</jsp:text>

模板的主体不能包含其他元素;它只能包含文本和 EL 表达式(注意 - EL 表达式将在后续章节中解释)。请注意,在 XML 文件中,您不能使用诸如 ${whatever > 0} 之类的表达式,因为大于号是非法的。相反,使用 gt 形式,例如 ${whatever gt 0} 或另一种方法是将值嵌入到 CDATA 部分中。

<jsp:text><![CDATA[<br>]]></jsp:text>

如果您需要包含一个DOCTYPE声明,例如对于XHTML,您也必须使用<jsp:text>元素,如下所示:

<jsp:text><![CDATA[<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "DTD/xhtml1-strict.dtd">]]></jsp:text>

   <head><title>jsp:text action</title></head>
   
   <body>
      <books><book><jsp:text>  
         Welcome to JSP Programming
      </jsp:text></book></books>
   </body>
</html>

尝试使用和不使用<jsp:text>操作来运行上面的示例。

JSP - 隐式对象

在本章中,我们将讨论JSP中的隐式对象。这些对象是JSP容器在每个页面中提供给开发人员的Java对象,开发人员可以直接调用它们,而无需显式声明。JSP隐式对象也称为预定义变量

下表列出了JSP支持的九个隐式对象:

序号 对象和说明
1

request

这是与请求关联的HttpServletRequest对象。

2

response

这是与对客户端的响应关联的HttpServletResponse对象。

3

out

这是用于向客户端发送输出的PrintWriter对象。

4

session

这是与请求关联的HttpSession对象。

5

application

这是与应用程序上下文关联的ServletContext对象。

6

config

这是与页面关联的ServletConfig对象。

7

pageContext

它封装了服务器特定功能的使用,例如更高性能的JspWriters

8

page

这仅仅是this的同义词,用于调用翻译后的Servlet类定义的方法。

9

Exception

Exception对象允许通过指定的JSP访问异常数据。

request对象

request对象是javax.servlet.http.HttpServletRequest对象的实例。每次客户端请求页面时,JSP引擎都会创建一个新的对象来表示该请求。

request对象提供方法来获取HTTP标头信息,包括表单数据、cookie、HTTP方法等。

我们可以在后续章节中介绍与request对象相关的一整套方法:JSP - 客户端请求

response对象

response对象是javax.servlet.http.HttpServletResponse对象的实例。就像服务器创建request对象一样,它还会创建一个对象来表示对客户端的响应。

response对象还定义了处理创建新的HTTP标头的接口。通过此对象,JSP程序员可以添加新的cookie或日期戳、HTTP状态代码等。

我们将在后续章节中介绍与response对象相关的一整套方法:JSP - 服务器响应

out对象

out隐式对象是javax.servlet.jsp.JspWriter对象的实例,用于在响应中发送内容。

根据页面是否已缓冲,初始的JspWriter对象实例化的方式不同。可以通过使用页面指令的buffered = 'false'属性轻松关闭缓冲。

JspWriter对象包含与java.io.PrintWriter类大部分相同的方法。但是,JspWriter有一些额外的方法用于处理缓冲。与PrintWriter对象不同,JspWriter会抛出IOExceptions

下表列出了我们将用于写入布尔值、字符、整数、双精度数、对象、字符串等的重要方法。

序号 方法及描述
1

out.print(dataType dt)

打印数据类型值

2

out.println(dataType dt)

打印数据类型值,然后用换行符终止该行。

3

out.flush()

刷新流。

session对象

session对象是javax.servlet.http.HttpSession的实例,其行为与Java Servlet中的session对象完全相同。

session对象用于在客户端请求之间跟踪客户端会话。我们将在后续章节中介绍session对象的完整用法:JSP - 会话跟踪

application对象

application对象是生成的Servlet的ServletContext对象的直接包装器,实际上是javax.servlet.ServletContext对象的实例。

此对象在其整个生命周期中表示JSP页面。此对象在JSP页面初始化时创建,并在JSP页面被jspDestroy()方法移除时移除。

通过向application添加属性,您可以确保构成Web应用程序的所有JSP文件都可以访问它。

我们将在JSP - 点击计数器章节中检查Application对象的用法。

config对象

config对象是javax.servlet.ServletConfig的实例化,是生成的servlet的ServletConfig对象的直接包装器。

此对象允许JSP程序员访问Servlet或JSP引擎初始化参数,例如路径或文件位置等。

以下是您可能唯一会使用到的config方法,其用法非常简单:

config.getServletName();

这将返回servlet名称,即WEB-INF\web.xml文件中定义的<servlet-name>元素中包含的字符串。

pageContext对象

pageContext对象是javax.servlet.jsp.PageContext对象的实例。pageContext对象用于表示整个JSP页面。

此对象旨在作为一种访问页面信息的方式,同时避免大多数实现细节。

此对象存储对每个请求的request和response对象的引用。application、config、session和out对象都是通过访问此对象的属性派生的。

pageContext对象还包含有关发出到JSP页面的指令的信息,包括缓冲信息、errorPageURL和页面范围。

PageContext类定义了几个字段,包括PAGE_SCOPE、REQUEST_SCOPE、SESSION_SCOPEAPPLICATION_SCOPE,它们标识四个范围。它还支持40多种方法,其中大约一半是从javax.servlet.jsp.JspContext类继承的。

其中一个重要的方法是removeAttribute。此方法接受一个或两个参数。例如,pageContext.removeAttribute ("attrName")将从所有范围内删除属性,而以下代码仅将其从页面范围内删除:

pageContext.removeAttribute("attrName", PAGE_SCOPE);

可以在JSP - 文件上传章节中查看pageContext的用法。

page对象

此对象是对页面的实例的实际引用。可以将其视为表示整个JSP页面的对象。

page对象实际上是this对象的同义词。

exception对象

exception对象是一个包装器,包含从前一个页面抛出的异常。它通常用于生成对错误情况的适当响应。

我们将在JSP - 异常处理章节中介绍此对象的完整用法。

JSP - 客户端请求

在本章中,我们将讨论JSP中的客户端请求。当浏览器请求网页时,它会向Web服务器发送大量信息。无法直接读取这些信息,因为这些信息作为HTTP请求标头的一部分传输。您可以查看HTTP协议以获取更多信息。

下表列出了来自浏览器的重要的标头信息。这些信息在Web编程中经常使用:

序号 标头及描述
1

Accept

此标头指定浏览器或其他客户端可以处理的MIME类型。image/pngimage/jpeg的值是最常见的两种可能性。

2

Accept-Charset

此标头指定浏览器可以使用哪些字符集来显示信息。例如,ISO-8859-1

3

Accept-Encoding

此标头指定浏览器知道如何处理的编码类型。gzipcompress的值是最常见的两种可能性。

4

Accept-Language

如果servlet可以用多种语言生成结果,则此标头指定客户端的首选语言。例如en、en-us、ru等。

5

Authorization

此标头用于客户端在访问受密码保护的网页时识别自己。

6

Connection

此标头指示客户端是否可以处理持久性HTTP连接。持久性连接允许客户端或其他浏览器使用单个请求检索多个文件。Keep-Alive的值表示应使用持久性连接。

7

Content-Length

此标头仅适用于POST请求,并以字节为单位给出POST数据的尺寸。

8

Cookie

此标头将cookie返回给之前将其发送到浏览器的服务器。

9

Host

此标头指定原始URL中给出的主机和端口。

10

If-Modified-Since

此标头指示客户端仅在指定日期之后页面发生更改时才需要页面。如果不存在更新的结果,服务器将发送代码304,这意味着未修改标头。

11

If-Unmodified-Since

此标头与If-Modified-Since相反;它指定操作仅在文档早于指定日期时才应成功。

12

Referer

此标头指示引用网页的URL。例如,如果您位于网页1并点击指向网页2的链接,则当浏览器请求网页2时,网页1的URL将包含在Referer标头中。

13

User-Agent

此标头标识发出请求的浏览器或其他客户端,可用于向不同类型的浏览器返回不同的内容。

HttpServletRequest对象

request对象是javax.servlet.http.HttpServletRequest对象的实例。每次客户端请求页面时,JSP引擎都会创建一个新的对象来表示该请求。

request对象提供方法来获取HTTP标头信息,包括表单数据、cookie、HTTP方法等。

下表列出了可用于在JSP程序中读取HTTP标头的重要方法。这些方法可用于表示客户端对Web服务器请求的HttpServletRequest对象。

序号 方法及描述
1

Cookie[] getCookies()

返回一个包含客户端随此请求发送的所有Cookie对象的数组。

2

Enumeration getAttributeNames()

返回一个包含此请求可用的属性名称的枚举。

3

Enumeration getHeaderNames()

返回此请求包含的所有标头名称的枚举。

4

Enumeration getParameterNames()

返回一个包含此请求中包含的参数名称的String对象的枚举。

5

HttpSession getSession()

返回与此请求关联的当前会话,或者如果请求没有会话,则创建一个新的会话。

6

HttpSession getSession(boolean create)

返回与此请求关联的当前HttpSession,或者如果不存在当前会话且create为true,则返回一个新的会话。

7

Locale getLocale()

根据Accept-Language标头返回客户端将接受内容的首选Locale。

8

Object getAttribute(String name)

返回值为指定名称的属性,如果不存在给定名称的属性,则返回null。

9

ServletInputStream getInputStream()

使用ServletInputStream检索请求的主体作为二进制数据。

10

String getAuthType()

返回用于保护servlet的身份验证方案的名称,例如“BASIC”或“SSL”,或者如果JSP未受保护,则返回null。

11

String getCharacterEncoding()

返回在此请求主体中使用的字符编码的名称。

12

String getContentType()

返回请求主体的MIME类型,或者如果类型未知,则返回null。

13

String getContextPath()

返回请求URI中指示请求上下文的片段。

14

String getHeader(String name)

返回值为指定请求标头的值。

15

String getMethod()

返回发出此请求的HTTP方法的名称,例如GET、POST或PUT。

16

String getParameter(String name)

返回值为请求参数的值,或者如果参数不存在,则返回null。

17

String getPathInfo()

返回客户端在发出此请求时发送的 URL 中关联的任何额外路径信息。

18

String getProtocol()

返回请求使用的协议的名称和版本。

19

String getQueryString()

返回请求 URL 中路径之后包含的查询字符串。

20

String getRemoteAddr()

返回发送请求的客户端的互联网协议 (IP) 地址。

21

String getRemoteHost()

返回发送请求的客户端的完全限定域名。

22

String getRemoteUser()

如果用户已通过身份验证,则返回发出此请求的用户的登录名;如果用户未通过身份验证,则返回 null。

23

String getRequestURI()

返回此请求的 URL 中从协议名称到 HTTP 请求第一行中的查询字符串的部分。

24

String getRequestedSessionId()

返回客户端指定的会话 ID。

25

String getServletPath()

返回此请求的 URL 中调用 JSP 的部分。

26

String[] getParameterValues(String name)

返回一个包含给定请求参数的所有值的 String 对象数组,如果参数不存在,则返回 null。

27

boolean isSecure()

返回一个布尔值,指示此请求是否使用安全通道(例如 HTTPS)发出。

28

int getContentLength()

返回请求正文的长度(以字节为单位),并通过输入流提供,如果长度未知,则返回 -1。

29

int getIntHeader(String name)

将指定请求头的值作为 int 返回。

30

int getServerPort()

返回接收此请求的端口号。

HTTP 头请求示例

以下示例使用 HttpServletRequestgetHeaderNames() 方法读取 HTTP 头信息。此方法返回一个包含与当前 HTTP 请求关联的头信息的枚举。

获得枚举后,我们可以以标准方式循环遍历枚举。我们将使用 hasMoreElements() 方法确定何时停止,并使用 nextElement() 方法获取每个参数名称的名称。

<%@ page import = "java.io.*,java.util.*" %>

<html>
   <head>
      <title>HTTP Header Request Example</title>
   </head>

   <body>
      <center>
         <h2>HTTP Header Request Example</h2>
         
         <table width = "100%" border = "1" align = "center">
            <tr bgcolor = "#949494">
               <th>Header Name</th>
               <th>Header Value(s)</th>
            </tr>
            <%
               Enumeration headerNames = request.getHeaderNames();
               while(headerNames.hasMoreElements()) {
                  String paramName = (String)headerNames.nextElement();
                  out.print("<tr><td>" + paramName + "</td>\n");
                  String paramValue = request.getHeader(paramName);
                  out.println("<td> " + paramValue + "</td></tr>\n");
               }
            %>
         </table>
      </center>
   
   </body>
</html>

现在让我们将上述代码放入 main.jsp 中并尝试访问它。

HTTP 头请求示例

头名称 头值
accept */*
accept-language en-us
user-agent Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; InfoPath.2; MS-RTC LM 8)
accept-encoding gzip, deflate
host localhost:8080
connection Keep-Alive
cache-control no-cache

您可以尝试以类似的方式处理所有方法。

JSP - 服务器响应

在本章中,我们将讨论 JSP 中的服务器响应。当 Web 服务器响应 HTTP 请求时,响应通常包含状态行、一些响应头、空行和文档。典型的响应如下所示:

HTTP/1.1 200 OK
Content-Type: text/html
Header2: ...
...
HeaderN: ...
   (Blank Line)
<!doctype ...>

<html>
   <head>...</head>
   <body>
      ...
   </body>
</html>

状态行由 HTTP 版本(示例中为 HTTP/1.1)、状态代码(示例中为 200)和与状态代码相对应的一条非常简短的消息(示例中为 OK)组成。

以下是返回到浏览器中从 Web 服务器返回的最有用的 HTTP 1.1 响应头的摘要。这些标头在 Web 编程中经常使用:

序号 标头及描述
1

Allow

此标头指定服务器支持的请求方法(GET、POST 等)。

2

Cache-Control

此标头指定可以安全缓存响应文档的情况。它可以具有值public、privateno-cache 等。Public 表示文档可缓存,Private 表示文档仅供单个用户使用,并且只能存储在私有(非共享)缓存中,no-cache 表示文档永远不应缓存。

3

Connection

此标头指示浏览器是否使用持久性 HTTP 连接。值为 close 指示浏览器不使用持久性 HTTP 连接,keep-alive 表示使用持久性连接。

4

Content-Disposition

此标头允许您请求浏览器要求用户将响应保存到具有给定名称的文件的磁盘中。

5

Content-Encoding

此标头指定在传输过程中页面编码的方式。

6

Content-Language

此标头表示文档的书写语言。例如,en、en-us、ru 等。

7

Content-Length

此标头指示响应中的字节数。只有当浏览器使用持久性 (keep-alive) HTTP 连接时,才需要此信息。

8

Content-Type

此标头提供响应文档的MIME多用途互联网邮件扩展)类型。

9

Expires

此标头指定内容应被视为过时且不再缓存的时间。

10

Last-Modified

此标头指示文档上次更改的时间。然后,客户端可以缓存文档并在以后的请求中通过 If-Modified-Since 请求头提供日期。

11

Location

此标头应包含在所有具有 300 多状态代码的响应中。这会通知浏览器文档地址。浏览器会自动重新连接到此位置并检索新文档。

12

Refresh

此标头指定浏览器应请求更新页面的时间。您可以指定页面刷新后的秒数。

13

Retry-After

此标头可以与 503(服务不可用)响应一起使用,以告诉客户端它可以何时重复其请求。

14

Set-Cookie

此标头指定与页面关联的 Cookie。

HttpServletResponse 对象

响应对象是 javax.servlet.http.HttpServletResponse 对象的实例。就像服务器创建请求对象一样,它还会创建一个对象来表示对客户端的响应。

响应对象还定义了用于创建新 HTTP 标头的接口。通过此对象,JSP 程序员可以添加新的 Cookie 或日期戳、HTTP 状态代码等。

以下方法可用于在 servlet 程序中设置 HTTP 响应头。这些方法可用于 HttpServletResponse 对象。此对象表示服务器响应。

序号 方法及描述
1

String encodeRedirectURL(String url)

对指定的 URL 进行编码,以便在 sendRedirect 方法中使用,或者如果不需要编码,则返回未更改的 URL。

2

String encodeURL(String url)

通过在其中包含会话 ID 对指定的 URL 进行编码,或者如果不需要编码,则返回未更改的 URL。

3

boolean containsHeader(String name)

返回一个布尔值,指示是否已设置命名响应头。

4

boolean isCommitted()

返回一个布尔值,指示响应是否已提交。

5

void addCookie(Cookie cookie)

将指定的 Cookie 添加到响应中。

6

void addDateHeader(String name, long date)

添加一个具有给定名称和日期值的响应头。

7

void addHeader(String name, String value)

添加一个具有给定名称和值的响应头。

8

void addIntHeader(String name, int value)

添加一个具有给定名称和整数值的响应头。

9

void flushBuffer()

强制将缓冲区中的任何内容写入客户端。

10

void reset()

清除缓冲区中存在的任何数据以及状态代码和标头。

11

void resetBuffer()

清除响应中底层缓冲区的内容,而不清除标头或状态代码。

12

void sendError(int sc)

使用指定的状态代码向客户端发送错误响应,并清除缓冲区。

13

void sendError(int sc, String msg)

使用指定的状态向客户端发送错误响应。

14

void sendRedirect(String location)

使用指定的重定向位置 URL 向客户端发送临时重定向响应。

15

void setBufferSize(int size)

设置响应正文的首选缓冲区大小。

16

void setCharacterEncoding(String charset)

设置发送到客户端的响应的字符编码(MIME 字符集),例如 UTF-8。

17

void setContentLength(int len)

设置响应中内容正文的长度在 HTTP servlet 中;此方法还会设置 HTTP Content-Length 标头。

18

void setContentType(String type)

设置发送到客户端的响应的内容类型,如果响应尚未提交。

19

void setDateHeader(String name, long date)

设置一个具有给定名称和日期值的响应头。

20

void setHeader(String name, String value)

设置一个具有给定名称和值的响应头。

21

void setIntHeader(String name, int value)

设置一个具有给定名称和整数值的响应头。

22

void setLocale(Locale loc)

设置响应的区域设置,如果响应尚未提交。

23

void setStatus(int sc)

设置此响应的状态代码。

HTTP 头响应示例

以下示例将使用 setIntHeader() 方法设置 Refresh 标头以模拟数字时钟:

<%@ page import = "java.io.*,java.util.*" %>

<html>
   
   <head>
      <title>Auto Refresh Header Example</title>
   </head>
   
   <body>
      <center>
         <h2>Auto Refresh Header Example</h2>
         <%
            // Set refresh, autoload time as 5 seconds
            response.setIntHeader("Refresh", 5);
            
            // Get current time
            Calendar calendar = new GregorianCalendar();
            
            String am_pm;
            int hour = calendar.get(Calendar.HOUR);
            int minute = calendar.get(Calendar.MINUTE);
            int second = calendar.get(Calendar.SECOND);
            
            if(calendar.get(Calendar.AM_PM) == 0) 
               am_pm = "AM";
            else
               am_pm = "PM";
               String CT = hour+":"+ minute +":"+ second +" "+ am_pm;
               out.println("Current Time is: " + CT + "\n");
         %>
      </center>
   
   </body>
</html>

现在将上述代码放入 main.jsp 中并尝试访问它。这将每 5 秒显示一次当前系统时间,如下所示。运行 JSP。您将收到以下输出:

Auto Refresh Header Example

Current Time is: 9:44:50 PM

您可以尝试以类似的方式处理其他方法。

JSP - HTTP 状态码

在本章中,我们将讨论 JSP 中的 HTTP 状态代码。HTTP 请求和 HTTP 响应消息的格式类似,将具有以下结构:

  • 初始状态行 + CRLF(回车 + 换行,即换行)

  • 零个或多个标头行 + CRLF

  • 空行,即 CRLF

  • 可选的消息正文,如文件、查询数据或查询输出。

例如,服务器响应头如下所示:

HTTP/1.1 200 OK
Content-Type: text/html
Header2: ...
...
HeaderN: ...
   (Blank Line)
<!doctype ...>

<html>
   <head>...</head>
   
   <body>
      ...
   </body>
</html>

状态行由 HTTP 版本(示例中为 HTTP/1.1)、状态代码(示例中为 200)和与状态代码相对应的一条非常简短的消息(示例中为 OK)组成。

下表列出了 Web 服务器可能返回的 HTTP 状态代码和关联消息:

代码 消息 描述
100 100 服务器仅接收了请求的一部分,但只要未被拒绝,客户端就应继续发出请求。
101 101 服务器切换协议。
200 200 请求成功。
201 201 请求已完成,并创建了一个新资源。
202 202 请求已接受处理,但处理尚未完成。
203 203
204 无内容。
205 服务器已成功处理请求,但未返回任何内容,并且希望客户端重置其文档视图。
206 服务器已成功处理了部分 GET 请求。
300 Multiple Choices 链接列表;用户可以选择一个链接并转到该位置。最多五个地址。
301 Moved Permanently 请求的页面已永久移动到新的 URL。
302 Found 请求的页面已临时移动到新的 URL。
303 See Other 请求的页面可以在不同的 URL 下找到。
304 请求的资源未修改。
305 请求的资源必须通过代理访问。
306 Unused 此代码在早期版本中使用过。它不再使用,但该代码已保留。
307 请求的资源已临时移动到不同的 URL,并且客户端应继续使用相同的请求方法进行重定向。 请求的页面已临时移动到新的 URL。
400 Bad Request 服务器不理解请求。
401 Unauthorized 请求的页面需要用户名和密码。
402 Payment Required 您尚不能使用此代码。
403 Forbidden 禁止访问请求的页面。
404 Not Found 服务器找不到请求的页面。
405 Method Not Allowed 请求中指定的方法不允许。
406 Not Acceptable 服务器只能生成客户端不接受的响应。
407 Proxy Authentication Required 在提供此请求之前,您必须对代理服务器进行身份验证。
408 Request Timeout 请求花费的时间超过了服务器准备等待的时间。
409 Conflict 由于冲突,无法完成请求。
410 Gone 请求的页面不再可用。
411 长度要求 "Content-Length" 未定义。服务器在没有此字段的情况下不会接受请求。
412 前提条件失败 服务器评估请求中给定的前提条件为假。
413 请求实体过大 服务器不会接受请求,因为请求实体过大。
414 请求URL过长 服务器不会接受请求,因为URL过长。当您将"post"请求转换为带有长查询信息的"get"请求时,就会发生这种情况。
415 不支持的媒体类型 服务器不会接受请求,因为不支持媒体类型。
417 期望失败
500 内部服务器错误 请求未完成。服务器遇到了意外情况。
501 未实现 请求未完成。服务器不支持所需的功能。
502 错误网关 请求未完成。服务器从上游服务器收到了无效的响应。
503 服务不可用 请求未完成。服务器暂时过载或宕机。
504 网关超时 网关超时。
505 不支持的HTTP版本 服务器不支持"http协议"版本。

设置HTTP状态码的方法

以下方法可用于在servlet程序中设置HTTP状态码。这些方法可通过HttpServletResponse对象使用。

序号 方法及描述
1

public void setStatus ( int statusCode )

此方法设置任意状态码。setStatus方法以int(状态码)作为参数。如果您的响应包含特殊状态码和文档,请确保在使用PrintWriter实际返回任何内容之前调用setStatus

2

public void sendRedirect(String url)

此方法生成302响应以及一个Location标头,其中提供了新文档的URL。

3

public void sendError(int code, String message)

此方法发送状态码(通常为404)以及一条简短消息,该消息会自动格式化为HTML文档并发送到客户端。

HTTP状态码示例

以下示例显示如何将407错误代码发送到客户端浏览器。之后,浏览器将显示"需要身份验证!!!"消息。

<html>
   <head>
      <title>Setting HTTP Status Code</title>
   </head>
   
   <body>
      <%
         // Set error code and reason.
         response.sendError(407, "Need authentication!!!" );
      %>
   </body>
</html>

您将收到以下输出:

HTTP Status 407 - Need authentication!!!

type Status report

message Need authentication!!!

description The client must first authenticate itself with the proxy (Need authentication!!!).

Apache Tomcat/5.5.29

要更熟悉HTTP状态码,请尝试设置不同的状态码及其描述。

JSP - 表单处理

在本章中,我们将讨论JSP中的表单处理。您肯定遇到过许多需要将一些信息从浏览器传递到Web服务器,最终传递到后端程序的情况。浏览器使用两种方法将此信息传递到Web服务器。这些方法是GET方法和POST方法。

表单处理中的方法

现在让我们讨论表单处理中的方法。

GET方法

GET方法发送附加到页面请求的编码用户信息。页面和编码信息由?字符分隔,如下所示:

http://www.test.com/hello?key1=value1&key2=value2

GET方法是将信息从浏览器传递到Web服务器的默认方法,它会生成一个出现在浏览器位置:框中的长字符串。建议最好不要使用GET方法,如果您需要将密码或其他敏感信息传递到服务器。

GET方法有大小限制:请求字符串中只能包含1024个字符

此信息使用QUERY_STRING标头传递,可以通过QUERY_STRING环境变量访问,可以使用请求对象的getQueryString()getParameter()方法进行处理。

POST方法

将信息传递到后端程序的更可靠的方法通常是POST方法。

此方法以与GET方法完全相同的方式打包信息,但它不是将其作为文本字符串附加到URL中的?之后发送,而是将其作为单独的消息发送。此消息以标准输入的形式到达后端程序,您可以对其进行解析并用于处理。

JSP使用getParameter()方法处理此类请求以读取简单参数,并使用getInputStream()方法读取来自客户端的二进制数据流。

使用JSP读取表单数据

JSP根据情况自动处理表单数据解析,使用以下方法:

  • getParameter() - 您调用request.getParameter()方法获取表单参数的值。

  • getParameterValues() - 如果参数出现多次并返回多个值,例如复选框,则调用此方法。

  • getParameterNames() - 如果您想要当前请求中所有参数的完整列表,则调用此方法。

  • getInputStream() - 调用此方法读取来自客户端的二进制数据流。

使用URL的GET方法示例

以下URL将使用GET方法将两个值传递给HelloForm程序。

https://127.0.0.1:8080/main.jsp?first_name=ZARA&last_name=ALI

以下是处理Web浏览器提供的输入的main.jsp JSP程序。我们将使用getParameter()方法,这使得访问传递的信息变得非常容易:

<html>
   <head>
      <title>Using GET Method to Read Form Data</title>
   </head>
   
   <body>
      <h1>Using GET Method to Read Form Data</h1>
      <ul>
         <li><p><b>First Name:</b>
            <%= request.getParameter("first_name")%>
         </p></li>
         <li><p><b>Last  Name:</b>
            <%= request.getParameter("last_name")%>
         </p></li>
      </ul>
   
   </body>
</html>

现在在浏览器的位置:框中输入https://127.0.0.1:8080/main.jsp?first_name=ZARA&last_name=ALI。这将生成以下结果:

使用GET方法读取表单数据

  • 名字:ZARA

  • 姓氏:ALI

使用表单的GET方法示例

以下是一个使用HTML表单和提交按钮传递两个值的示例。我们将使用相同的JSP main.jsp来处理此输入。

<html>
   <body>
      
      <form action = "main.jsp" method = "GET">
         First Name: <input type = "text" name = "first_name">
         <br />
         Last Name: <input type = "text" name = "last_name" />
         <input type = "submit" value = "Submit" />
      </form>
      
   </body>
</html>

将此HTML保存在名为Hello.htm的文件中,并将其放在<Tomcat-安装目录>/webapps/ROOT目录中。当您访问https://127.0.0.1:8080/Hello.htm时,您将收到以下输出。

名字
姓氏
< p>尝试输入名字和姓氏,然后单击提交按钮以查看Tomcat正在运行的本地计算机上的结果。根据提供的输入,它将生成与上述示例类似的结果。

使用表单的POST方法示例

让我们对上述JSP进行一些修改以处理GET和POST方法。以下是处理Web浏览器使用GET或POST方法提供的输入的main.jsp JSP程序。

实际上,上述JSP没有变化,因为传递参数的唯一方式发生了变化,并且没有二进制数据被传递到JSP程序。与文件处理相关的概念将在单独的章节中解释,在这些章节中我们需要读取二进制数据流。

<html>
   <head>
      <title>Using GET and POST Method to Read Form Data</title>
   </head>
   
   <body>
      <center>
      <h1>Using POST Method to Read Form Data</h1>
      
      <ul>
         <li><p><b>First Name:</b>
            <%= request.getParameter("first_name")%>
         </p></li>
         <li><p><b>Last  Name:</b>
            <%= request.getParameter("last_name")%>
         </p></li>
      </ul>
   
   </body>
</html>

以下是Hello.htm文件的内容:

<html>
   <body>
      
      <form action = "main.jsp" method = "POST">
         First Name: <input type = "text" name = "first_name">
         <br />
         Last Name: <input type = "text" name = "last_name" />
         <input type = "submit" value = "Submit" />
      </form>
      
   </body>
</html>

现在让我们将main.jsp和hello.htm放在<Tomcat-安装目录>/webapps/ROOT目录中。当您访问https://127.0.0.1:8080/Hello.htm时,您将收到以下输出。

名字
姓氏

尝试输入名字和姓氏,然后单击提交按钮以查看Tomcat正在运行的本地计算机上的结果。

根据提供的输入,您将收到与上述示例类似的结果。

将复选框数据传递到JSP程序

当需要选择多个选项时,使用复选框。

以下是带有两个复选框的表单的示例HTML代码,CheckBox.htm

<html>
   <body>
      
      <form action = "main.jsp" method = "POST" target = "_blank">
         <input type = "checkbox" name = "maths" checked = "checked" /> Maths
         <input type = "checkbox" name = "physics"  /> Physics
         <input type = "checkbox" name = "chemistry" checked = "checked" /> Chemistry
         <input type = "submit" value = "Select Subject" />
      </form>
      
   </body>
</html>

上述代码将生成以下结果:

数学物理化学

以下是处理Web浏览器为复选框按钮提供的输入的main.jsp JSP程序。

<html>
   <head>
      <title>Reading Checkbox Data</title>
   </head>
   
   <body>
      <h1>Reading Checkbox Data</h1>
      
      <ul>
         <li><p><b>Maths Flag:</b>
            <%= request.getParameter("maths")%>
         </p></li>
         <li><p><b>Physics Flag:</b>
            <%= request.getParameter("physics")%>
         </p></li>
         <li><p><b>Chemistry Flag:</b>
            <%= request.getParameter("chemistry")%>
         </p></li>
      </ul>
   
   </body>
</html>

上述程序将生成以下结果:

Reading Checkbox Data

  • Maths Flag :: on

  • Physics Flag:: null

  • Chemistry Flag:: on

读取所有表单参数

以下是一个通用示例,它使用HttpServletRequest的getParameterNames()方法读取所有可用的表单参数。此方法返回一个Enumeration,其中包含参数名称,但顺序未指定。

获得Enumeration后,我们可以使用标准方式遍历Enumeration,使用hasMoreElements()方法确定何时停止,并使用nextElement()方法获取每个参数名称。

<%@ page import = "java.io.*,java.util.*" %>

<html>
   <head>
      <title>HTTP Header Request Example</title>
   </head>

   <body>
      <center>
         <h2>HTTP Header Request Example</h2>
         <table width = "100%" border = "1" align = "center">
            <tr bgcolor = "#949494">
               <th>Param Name</th>
               <th>Param Value(s)</th>
            </tr>
            <%
               Enumeration paramNames = request.getParameterNames();
               while(paramNames.hasMoreElements()) {
                  String paramName = (String)paramNames.nextElement();
                  out.print("<tr><td>" + paramName + "</td>\n");
                  String paramValue = request.getHeader(paramName);
                  out.println("<td> " + paramValue + "</td></tr>\n");
               }
            %>
         </table>
      </center>
   
   </body>
</html>

以下是Hello.htm的内容:

<html>
   <body>
      
      <form action = "main.jsp" method = "POST" target = "_blank">
         <input type = "checkbox" name = "maths" checked = "checked" /> Maths
         <input type = "checkbox" name = "physics"  /> Physics
         <input type = "checkbox" name = "chemistry" checked = "checked" /> Chem
         <input type = "submit" value = "Select Subject" />
      </form>
   
   </body>
</html>

现在尝试使用上述Hello.htm调用JSP;这将根据提供的输入生成类似于以下的结果:

读取所有表单参数

参数名称 参数值(s)
数学 开启
化学 开启

您可以尝试使用上述JSP读取任何其他表单的数据,这些表单包含其他对象,例如文本框、单选按钮或下拉列表等。

JSP - 过滤器

在本章中,我们将讨论JSP中的过滤器。Servlet和JSP过滤器是Java类,可以在Servlet和JSP编程中用于以下目的:

  • 在客户端访问后端资源之前拦截来自客户端的请求。

  • 在服务器将响应发送回客户端之前操作响应。

规范建议有各种类型的过滤器:

  • 身份验证过滤器
  • 数据压缩过滤器
  • 加密过滤器
  • 触发资源访问事件的过滤器
  • 图像转换过滤器
  • 日志记录和审计过滤器
  • MIME-TYPE链过滤器
  • 标记化过滤器
  • 转换XML内容的XSL/T过滤器

过滤器部署在部署描述符文件web.xml中,然后映射到应用程序部署描述符中的servlet或JSP名称或URL模式。部署描述符文件web.xml可以在<Tomcat-安装目录>\conf目录中找到。

当JSP容器启动您的Web应用程序时,它会创建您在部署描述符中声明的每个过滤器的实例。过滤器按其在部署描述符中声明的顺序执行。

Servlet过滤器方法

过滤器只是一个实现javax.servlet.Filter接口的Java类。javax.servlet.Filter接口定义了三种方法:

序号 方法及描述
1

public void doFilter (ServletRequest, ServletResponse, FilterChain)

每次由于客户端对链末端资源的请求而通过链传递请求/响应对时,容器都会调用此方法。

2

public void init(FilterConfig filterConfig)

Web容器调用此方法以指示过滤器正在被投入使用。

3

public void destroy()

Web容器调用此方法以指示过滤器正在被停止使用。

JSP过滤器示例

以下示例显示了如何每次访问任何JSP文件时打印客户端的IP地址和当前日期时间。此示例将为您提供对JSP过滤器的基本了解,但您可以使用相同的概念编写更复杂的过滤器应用程序:

// Import required java libraries
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
 
// Implements Filter class
public class LogFilter implements Filter  {
   public void  init(FilterConfig config) throws ServletException {
      // Get init parameter 
      String testParam = config.getInitParameter("test-param"); 
 
      //Print the init parameter 
      System.out.println("Test Param: " + testParam); 
   }
   public void  doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
      throws java.io.IOException, ServletException {
      
      // Get the IP address of client machine.   
      String ipAddress = request.getRemoteAddr();
      
      // Log the IP address and current timestamp.
      System.out.println("IP "+ ipAddress + ", Time "+ new Date().toString());
      
      // Pass request back down the filter chain
      chain.doFilter(request,response);
   }
   public void destroy( ) {
      /* Called before the Filter instance is removed 
      from service by the web container*/
   }
}

以通常的方式编译LogFilter.java,并将您的LogFilter.class文件放在<Tomcat-安装目录>/webapps/ROOT/WEB-INF/classes中。

Web.xml中的JSP过滤器映射

过滤器定义后,映射到URL或JSP文件名,这与Servlet定义后映射到URL模式的方式非常相似,在web.xml文件中。在部署描述符文件web.xml中创建以下过滤器标签条目

<filter>
   <filter-name>LogFilter</filter-name>
   <filter-class>LogFilter</filter-class>
   
   <init-param>
      <param-name>test-param</param-name>
      <param-value>Initialization Paramter</param-value>
   </init-param>
</filter>

<filter-mapping>
   <filter-name>LogFilter</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

上述过滤器将应用于所有servlet和JSP,因为我们在配置中指定了/*。如果您只想对少数servlet或JSP应用过滤器,则可以指定特定的servlet或JSP路径。

现在尝试调用任何servlet或JSP,您将在Web服务器日志中看到生成的日志。您可以使用Log4J记录器将上述日志记录到单独的文件中。

使用多个过滤器

您的 Web 应用程序可能定义了几个具有特定用途的不同过滤器。例如,您定义了两个过滤器AuthenFilterLogFilter。除了需要创建如下所述的不同映射之外,其余过程将保持与上面解释的相同。

<filter>
   <filter-name>LogFilter</filter-name>
   <filter-class>LogFilter</filter-class>
   
   <init-param>
      <param-name>test-param</param-name>
      <param-value>Initialization Paramter</param-value>
   </init-param>
</filter>
 
<filter>
   <filter-name>AuthenFilter</filter-name>
   <filter-class>AuthenFilter</filter-class>
   <init-param>
      <param-name>test-param</param-name>
      <param-value>Initialization Paramter</param-value>
   </init-param>
</filter>
 
<filter-mapping>
   <filter-name>LogFilter</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>
 
<filter-mapping>
   <filter-name>AuthenFilter</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

过滤器应用程序顺序

web.xml 中过滤器映射元素的顺序决定了 Web 容器将过滤器应用于 servlet 或 JSP 的顺序。要反转过滤器的顺序,您只需要反转web.xml文件中的过滤器映射元素即可。

例如,上面的示例将首先应用 LogFilter,然后将其应用于任何 servlet 或 JSP;下面的示例将反转顺序:

<filter-mapping>
   <filter-name>AuthenFilter</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>
 
<filter-mapping>
   <filter-name>LogFilter</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

JSP - 处理 Cookie

在本章中,我们将讨论 JSP 中的 Cookie 处理。Cookie 是存储在客户端计算机上的文本文件,它们用于各种信息跟踪目的。JSP 使用底层的 servlet 技术透明地支持 HTTP Cookie。

识别和返回用户涉及三个步骤:

  • 服务器脚本向浏览器发送一组 Cookie。例如,名称、年龄或识别号等。

  • 浏览器将此信息存储在本地机器上以供将来使用。

  • 当浏览器下次向 Web 服务器发送任何请求时,它会将这些 Cookie 信息发送到服务器,服务器使用这些信息来识别用户,或者可能用于其他目的。

本章将教您如何使用 JSP 程序设置或重置 Cookie、如何访问它们以及如何删除它们。

Cookie 的结构

Cookie 通常设置在 HTTP 标头中(尽管 JavaScript 也可以直接在浏览器上设置 Cookie)。设置 Cookie 的 JSP 可能发送如下所示的标头:

HTTP/1.1 200 OK
Date: Fri, 04 Feb 2000 21:03:38 GMT
Server: Apache/1.3.9 (UNIX) PHP/4.0b3
Set-Cookie: name = xyz; expires = Friday, 04-Feb-07 22:03:38 GMT; 
   path = /; domain = tutorialspoint.com
Connection: close
Content-Type: text/html

如您所见,Set-Cookie 标头包含名称值对、GMT 日期、路径。名称和值将进行 URL 编码。expires字段是指示浏览器在给定的时间和日期后“忘记”Cookie 的指令。

如果浏览器配置为存储 Cookie,则它会将此信息保留到过期日期。如果用户将浏览器指向与 Cookie 的路径和域匹配的任何页面,它将重新发送 Cookie 到服务器。浏览器的标头可能如下所示:

GET / HTTP/1.0
Connection: Keep-Alive
User-Agent: Mozilla/4.6 (X11; I; Linux 2.2.6-15apmac ppc)
Host: zink.demon.co.uk:1126

Accept: image/gif, */*
Accept-Encoding: gzip
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8
Cookie: name = xyz

然后,JSP 脚本可以通过请求方法request.getCookies()访问 Cookie,该方法返回一个Cookie对象的数组。

Servlet Cookie 方法

下表列出了与 Cookie 对象相关的一些有用方法,您可以在 JSP 中操作 Cookie 时使用这些方法:

序号 方法及描述
1

public void setDomain(String pattern)

此方法设置 Cookie 应用到的域;例如,tutorialspoint.com。

2

public String getDomain()

此方法获取 Cookie 应用到的域;例如,tutorialspoint.com。

3

public void setMaxAge(int expiry)

此方法设置 Cookie 过期前应经过多长时间(以秒为单位)。如果您不设置此值,则 Cookie 将仅持续当前会话。

4

public int getMaxAge()

此方法返回 Cookie 的最大年龄(以秒为单位),默认值为-1,表示 Cookie 将持续到浏览器关闭。

5

public String getName()

此方法返回 Cookie 的名称。创建后无法更改名称。

6

public void setValue(String newValue)

此方法设置与 Cookie 关联的值。

7

public String getValue()

此方法获取与 Cookie 关联的值。

8

public void setPath(String uri)

此方法设置此 Cookie 应用到的路径。如果您未指定路径,则 Cookie 将返回当前页面以及所有子目录中所有 URL。

9

public String getPath()

此方法获取此 Cookie 应用到的路径。

10

public void setSecure(boolean flag)

此方法设置布尔值,指示 Cookie 是否应仅通过加密(即 SSL)连接发送。

11

public void setComment(String purpose)

此方法指定描述 Cookie 目的的注释。如果浏览器将 Cookie 显示给用户,则注释很有用。

12

public String getComment()

此方法返回描述此 Cookie 目的的注释,如果 Cookie 没有注释,则返回 null。

使用 JSP 设置 Cookie

使用 JSP 设置 Cookie 涉及三个步骤:

步骤 1:创建 Cookie 对象

您使用 Cookie 名称和 Cookie 值(两者均为字符串)调用 Cookie 构造函数。

Cookie cookie = new Cookie("key","value");

请记住,名称和值都不应包含空格或以下任何字符:

[ ] ( ) = , " / ? @ : ;

步骤 2:设置最大年龄

您使用setMaxAge指定 Cookie 应有效多长时间(以秒为单位)。以下代码将设置 Cookie 24 小时。

cookie.setMaxAge(60*60*24); 

步骤 3:将 Cookie 发送到 HTTP 响应标头

您使用response.addCookie在 HTTP 响应标头中添加 Cookie,如下所示

response.addCookie(cookie);

示例

让我们修改我们的表单示例以设置姓氏和名字的 Cookie。

<%
   // Create cookies for first and last names.      
   Cookie firstName = new Cookie("first_name", request.getParameter("first_name"));
   Cookie lastName = new Cookie("last_name", request.getParameter("last_name"));
   
   // Set expiry date after 24 Hrs for both the cookies.
   firstName.setMaxAge(60*60*24); 
   lastName.setMaxAge(60*60*24); 
   
   // Add both the cookies in the response header.
   response.addCookie( firstName );
   response.addCookie( lastName );
%>

<html>
   <head>
      <title>Setting Cookies</title>
   </head>
   
   <body>
      <center>
         <h1>Setting Cookies</h1>
      </center>
      <ul>
         <li><p><b>First Name:</b>
            <%= request.getParameter("first_name")%>
         </p></li>
         <li><p><b>Last  Name:</b>
            <%= request.getParameter("last_name")%>
         </p></li>
      </ul>
   
   </body>
</html>

让我们将上述代码放在main.jsp文件中,并在以下 HTML 页面中使用它:

<html>
   <body>
      
      <form action = "main.jsp" method = "GET">
         First Name: <input type = "text" name = "first_name">
         <br />
         Last Name: <input type = "text" name = "last_name" />
         <input type = "submit" value = "Submit" />
      </form>
      
   </body>
</html>

将上述 HTML 内容保存在hello.jsp文件中,并将hello.jspmain.jsp放在<Tomcat-安装目录>/webapps/ROOT目录中。当您访问https://127.0.0.1:8080/hello.jsp时,以下是上述表单的实际输出。

名字
姓氏

尝试输入名字和姓氏,然后单击提交按钮。这将在屏幕上显示名字和姓氏,并设置两个 CookiefirstNamelastName。下次单击提交按钮时,这些 Cookie 将被传回服务器。

在下一节中,我们将解释如何在 Web 应用程序中访问这些 Cookie。

使用 JSP 读取 Cookie

要读取 Cookie,您需要通过调用HttpServletRequestgetCookies( )方法创建一个javax.servlet.http.Cookie对象的数组。然后遍历数组,并使用getName()getValue()方法访问每个 Cookie 和关联的值。

示例

现在让我们读取在上一个示例中设置的 Cookie:

<html>
   <head>
      <title>Reading Cookies</title>
   </head>
   
   <body>
      <center>
         <h1>Reading Cookies</h1>
      </center>
      <%
         Cookie cookie = null;
         Cookie[] cookies = null;
         
         // Get an array of Cookies associated with the this domain
         cookies = request.getCookies();
         
         if( cookies != null ) {
            out.println("<h2> Found Cookies Name and Value</h2>");
            
            for (int i = 0; i < cookies.length; i++) {
               cookie = cookies[i];
               out.print("Name : " + cookie.getName( ) + ",  ");
               out.print("Value: " + cookie.getValue( )+" <br/>");
            }
         } else {
            out.println("<h2>No cookies founds</h2>");
         }
      %>
   </body>
   
</html>

现在让我们将上述代码放在main.jsp文件中并尝试访问它。如果您将first_name Cookie设置为“John”,将last_name Cookie设置为“Player”,则运行https://127.0.0.1:8080/main.jsp将显示以下结果:

Found Cookies Name and Value

Name : first_name, Value: John

Name : last_name, Value: Player

使用 JSP 删除 Cookie

删除 Cookie 非常简单。如果您想删除 Cookie,则只需执行以下三个步骤:

  • 读取已存在的 Cookie 并将其存储在 Cookie 对象中。

  • 使用setMaxAge()方法将 Cookie 年龄设置为零以删除现有 Cookie。

  • 将此 Cookie 添加回响应标头。

示例

以下示例将向您展示如何删除名为“first_name”的现有 Cookie,以及下次运行 main.jsp JSP 时,它将为 first_name 返回 null 值。

<html>
   <head>
      <title>Reading Cookies</title>
   </head>
   
   <body>
      <center>
         <h1>Reading Cookies</h1>
      </center>
      <%
         Cookie cookie = null;
         Cookie[] cookies = null;
         
         // Get an array of Cookies associated with the this domain
         cookies = request.getCookies();
         
         if( cookies != null ) {
            out.println("<h2> Found Cookies Name and Value</h2>");
            
            for (int i = 0; i < cookies.length; i++) {
               cookie = cookies[i];
               
               if((cookie.getName( )).compareTo("first_name") == 0 ) {
                  cookie.setMaxAge(0);
                  response.addCookie(cookie);
                  out.print("Deleted cookie: " + 
                  cookie.getName( ) + "<br/>");
               }
               out.print("Name : " + cookie.getName( ) + ",  ");
               out.print("Value: " + cookie.getValue( )+" <br/>");
            }
         } else {
            out.println(
            "<h2>No cookies founds</h2>");
         }
      %>
   </body>
   
</html>

现在让我们将上述代码放在main.jsp文件中并尝试访问它。它将显示以下结果:

Cookies Name and Value

Deleted cookie : first_name

Name : first_name, Value: John

Name : last_name, Value: Player

现在再次运行https://127.0.0.1:8080/main.jsp,它应该只显示一个 Cookie,如下所示:

Found Cookies Name and Value

Name : last_name, Value: Player

您可以在 Internet Explorer 中手动删除 Cookie。从“工具”菜单开始,然后选择“Internet 选项”。要删除所有 Cookie,请单击“删除 Cookie”按钮。

JSP - 会话跟踪

在本章中,我们将讨论 JSP 中的会话跟踪。HTTP 是一种“无状态”协议,这意味着每次客户端检索网页时,客户端都会打开与 Web 服务器的单独连接,并且服务器不会自动保留任何先前客户端请求的记录。

维护 Web 客户端和服务器之间的会话

现在让我们讨论一些在 Web 客户端和 Web 服务器之间维护会话的选项:

Cookie

Web 服务器可以为每个 Web 客户端分配一个唯一的会话 ID 作为 Cookie,并且对于客户端的后续请求,可以使用接收到的 Cookie 识别它们。

这可能不是一种有效的方法,因为浏览器有时不支持 Cookie。不建议使用此过程来维护会话。

隐藏表单字段

Web 服务器可以发送一个隐藏的 HTML 表单字段以及一个唯一的会话 ID,如下所示:

<input type = "hidden" name = "sessionid" value = "12345">

此条目表示,当提交表单时,指定的名称和值将自动包含在GETPOST数据中。每次 Web 浏览器发送请求时,session_id值可用于跟踪不同的 Web 浏览器。

这可能是跟踪会话的一种有效方法,但单击常规(<A HREF...>)超文本链接不会导致表单提交,因此隐藏表单字段也不能支持常规会话跟踪。

URL 重写

您可以在每个 URL 的末尾附加一些额外的数据。此数据标识会话;服务器可以将该会话标识符与其存储的有关该会话的数据相关联。

例如,对于https://tutorialspoint.com/file.htm;sessionid=12345,会话标识符附加为sessionid = 12345,可以在 Web 服务器上访问以识别客户端。

URL 重写是维护会话的一种更好方法,并且在浏览器不支持 Cookie 时对浏览器有效。这里的缺点是您必须动态生成每个 URL 以分配会话 ID,即使页面是一个简单的静态 HTML 页面。

session对象

除了上述选项之外,JSP 还利用 servlet 提供的 HttpSession 接口。此接口提供了一种跨以下方面识别用户的方法。

  • 一个页面请求或
  • 访问网站或
  • 存储有关该用户的信息

默认情况下,JSP 已启用会话跟踪,并且会为每个新的客户端自动实例化一个新的 HttpSession 对象。禁用会话跟踪需要通过将页面指令 session 属性显式设置为 false 来关闭它,如下所示:

<%@ page session = "false" %>

JSP 引擎通过隐式session对象向 JSP 作者公开 HttpSession 对象。由于session对象已提供给 JSP 程序员,因此程序员可以立即开始从对象中存储和检索数据,而无需任何初始化或getSession()

以下是通过 session 对象可用的重要方法摘要:

序号 方法及描述
1

public Object getAttribute(String name)

此方法返回在此会话中与指定名称绑定的对象,如果名称下没有绑定任何对象,则返回 null。

2

public Enumeration getAttributeNames()

此方法返回一个 String 对象的 Enumeration,其中包含绑定到此会话的所有对象的名称。

3

public long getCreationTime()

此方法返回创建此会话的时间,以 1970 年 1 月 1 日午夜以来的毫秒数表示(格林威治标准时间)。

4

public String getId()

此方法返回一个字符串,其中包含分配给此会话的唯一标识符。

5

public long getLastAccessedTime()

此方法返回客户端上次发送与此会话关联的请求的时间,以 1970 年 1 月 1 日午夜以来的毫秒数表示(格林威治标准时间)。

6

public int getMaxInactiveInterval()

此方法返回 servlet 容器在客户端访问之间保持此会话打开的最大时间间隔(以秒为单位)。

7

public void invalidate()

此方法使此会话无效,并取消绑定与其绑定的任何对象。

8

public boolean isNew()

如果客户端尚不知道该会话或客户端选择不加入该会话,则此方法返回 true。

9

public void removeAttribute(String name)

此方法从此会话中删除与指定名称绑定的对象。

10

public void setAttribute(String name, Object value)

此方法使用指定的名称将对象绑定到此会话。

11

public void setMaxInactiveInterval(int interval)

此方法指定客户端请求之间的时间(以秒为单位),在此时间之后,servlet 容器将使此会话无效。

会话跟踪示例

此示例描述了如何使用 HttpSession 对象查找会话的创建时间和上次访问时间。如果不存在会话,我们将与请求关联一个新的会话。

<%@ page import = "java.io.*,java.util.*" %>
<%
   // Get session creation time.
   Date createTime = new Date(session.getCreationTime());
   
   // Get last access time of this Webpage.
   Date lastAccessTime = new Date(session.getLastAccessedTime());

   String title = "Welcome Back to my website";
   Integer visitCount = new Integer(0);
   String visitCountKey = new String("visitCount");
   String userIDKey = new String("userID");
   String userID = new String("ABCD");

   // Check if this is new comer on your Webpage.
   if (session.isNew() ){
      title = "Welcome to my website";
      session.setAttribute(userIDKey, userID);
      session.setAttribute(visitCountKey,  visitCount);
   } 
   visitCount = (Integer)session.getAttribute(visitCountKey);
   visitCount = visitCount + 1;
   userID = (String)session.getAttribute(userIDKey);
   session.setAttribute(visitCountKey,  visitCount);
%>

<html>
   <head>
      <title>Session Tracking</title>
   </head>
   
   <body>
      <center>
         <h1>Session Tracking</h1>
      </center>
      
      <table border = "1" align = "center"> 
         <tr bgcolor = "#949494">
            <th>Session info</th>
            <th>Value</th>
         </tr> 
         <tr>
            <td>id</td>
            <td><% out.print( session.getId()); %></td>
         </tr> 
         <tr>
            <td>Creation Time</td>
            <td><% out.print(createTime); %></td>
         </tr> 
         <tr>
            <td>Time of Last Access</td>
            <td><% out.print(lastAccessTime); %></td>
         </tr> 
         <tr>
            <td>User ID</td>
            <td><% out.print(userID); %></td>
         </tr> 
         <tr>
            <td>Number of visits</td>
            <td><% out.print(visitCount); %></td>
         </tr> 
      </table> 
   
   </body>
</html>

现在将以上代码放入 **main.jsp** 中,并尝试访问 **https://127.0.0.1:8080/main.jsp**。运行 URL 后,您将收到以下结果:

欢迎访问我的网站

会话信息

会话信息 value
ID 0AE3EC93FF44E3C525B4351B77ABB2D5
创建时间 2010 年 6 月 8 日星期二 17:26:40 GMT+04:00
上次访问时间 2010 年 6 月 8 日星期二 17:26:40 GMT+04:00
用户 ID ABCD
访问次数 0

现在尝试第二次运行相同的 JSP,您将收到以下结果。

欢迎再次访问我的网站

会话信息

信息类型 value
ID 0AE3EC93FF44E3C525B4351B77ABB2D5
创建时间 2010 年 6 月 8 日星期二 17:26:40 GMT+04:00
上次访问时间 2010 年 6 月 8 日星期二 17:26:40 GMT+04:00
用户 ID ABCD
访问次数 1

删除会话数据

完成用户会话数据后,您有以下几种选择:

  • **删除特定属性** - 您可以调用 **public void removeAttribute(String name)** 方法来删除与特定键关联的值。

  • **删除整个会话** - 您可以调用 **public void invalidate()** 方法来丢弃整个会话。

  • **设置会话超时** - 您可以调用 **public void setMaxInactiveInterval(int interval)** 方法为每个会话单独设置超时。

  • **注销用户** - 支持 servlet 2.4 的服务器,您可以调用 **logout** 将客户端注销 Web 服务器并使属于所有用户的全部会话失效。

  • **web.xml 配置** - 如果您使用的是 Tomcat,除了上述方法外,您还可以按如下方式在 web.xml 文件中配置会话超时。

<session-config>
   <session-timeout>15</session-timeout>
</session-config>

超时以分钟为单位表示,并覆盖 Tomcat 中的默认超时(30 分钟)。

servlet 中的 **getMaxInactiveInterval( )** 方法以秒为单位返回该会话的超时时间段。因此,如果您的会话在 web.xml 中配置为 15 分钟,则 **getMaxInactiveInterval( )** 返回 900。

JSP - 文件上传

在本节中,我们将讨论 JSP 中的文件上传。JSP 可以与 HTML 表单标签一起使用,允许用户将文件上传到服务器。上传的文件可以是文本文件、二进制文件、图像文件或任何文档。

创建文件上传表单

现在让我们了解如何创建文件上传表单。以下 HTML 代码创建了一个上传表单。以下是要注意的重要事项:

  • 表单的 **method** 属性应设置为 **POST** 方法,不能使用 GET 方法。

  • 表单的 **enctype** 属性应设置为 **multipart/form-data**。

  • 表单的 **action** 属性应设置为一个 JSP 文件,该文件将在后端服务器处理文件上传。以下示例使用 **uploadFile.jsp** 程序文件上传文件。

  • 要上传单个文件,您应该使用单个 **<input .../>** 标签,其属性 **type = "file"**。要允许上传多个文件,请包含多个 input 标签,并为 name 属性提供不同的值。浏览器为每个标签关联一个“浏览”按钮。

<html>
   <head>
      <title>File Uploading Form</title>
   </head>
   
   <body>
      <h3>File Upload:</h3>
      Select a file to upload: <br />
      <form action = "UploadServlet" method = "post"
         enctype = "multipart/form-data">
         <input type = "file" name = "file" size = "50" />
         <br />
         <input type = "submit" value = "Upload File" />
      </form>
   </body>
   
</html>

这将显示以下结果。您现在可以从本地 PC 选择一个文件,当用户点击“上传文件”时,表单将与所选文件一起提交:

File Upload

Select a file to upload −



**注意** - 以上表单只是一个虚拟表单,无法工作,您应该在您的机器上尝试以上代码才能使其工作。

编写后端 JSP 脚本

现在让我们定义一个上传文件将存储的位置。您可以在程序中硬编码此位置,或者也可以使用外部配置(例如 web.xml 中的 **context-param** 元素)添加此目录名称,如下所示:

<web-app>
....
<context-param> 
   <description>Location to store uploaded file</description> 
   <param-name>file-upload</param-name> 
   <param-value>
      c:\apache-tomcat-5.5.29\webapps\data\
   </param-value> 
</context-param>
....
</web-app>

以下是 **UploadFile.jsp** 的源代码。它可以一次处理多个文件的上传。在继续上传文件之前,让我们考虑以下几点。

  • 以下示例依赖于 **FileUpload**;确保您的类路径中包含最新版本的 **commons-fileupload.x.x.jar** 文件。您可以从 https://commons.apache.org/fileupload/ 下载它。

  • FileUpload 依赖于 Commons IO;确保您的类路径中包含最新版本的 **commons-io-x.x.jar** 文件。您可以从 https://commons.apache.org/io/ 下载它。

  • 在测试以下示例时,您应该上传大小小于 maxFileSize 的文件,否则文件将无法上传。

  • 确保您已提前创建了 **c:\temp** 和 **c:\apache-tomcat5.5.29\webapps\data** 目录。

<%@ page import = "java.io.*,java.util.*, javax.servlet.*" %>
<%@ page import = "javax.servlet.http.*" %>
<%@ page import = "org.apache.commons.fileupload.*" %>
<%@ page import = "org.apache.commons.fileupload.disk.*" %>
<%@ page import = "org.apache.commons.fileupload.servlet.*" %>
<%@ page import = "org.apache.commons.io.output.*" %>

<%
   File file ;
   int maxFileSize = 5000 * 1024;
   int maxMemSize = 5000 * 1024;
   ServletContext context = pageContext.getServletContext();
   String filePath = context.getInitParameter("file-upload");

   // Verify the content type
   String contentType = request.getContentType();
   
   if ((contentType.indexOf("multipart/form-data") >= 0)) {
      DiskFileItemFactory factory = new DiskFileItemFactory();
      // maximum size that will be stored in memory
      factory.setSizeThreshold(maxMemSize);
      
      // Location to save data that is larger than maxMemSize.
      factory.setRepository(new File("c:\\temp"));

      // Create a new file upload handler
      ServletFileUpload upload = new ServletFileUpload(factory);
      
      // maximum file size to be uploaded.
      upload.setSizeMax( maxFileSize );
      
      try { 
         // Parse the request to get file items.
         List fileItems = upload.parseRequest(request);

         // Process the uploaded file items
         Iterator i = fileItems.iterator();

         out.println("<html>");
         out.println("<head>");
         out.println("<title>JSP File upload</title>");  
         out.println("</head>");
         out.println("<body>");
         
         while ( i.hasNext () ) {
            FileItem fi = (FileItem)i.next();
            if ( !fi.isFormField () ) {
               // Get the uploaded file parameters
               String fieldName = fi.getFieldName();
               String fileName = fi.getName();
               boolean isInMemory = fi.isInMemory();
               long sizeInBytes = fi.getSize();
            
               // Write the file
               if( fileName.lastIndexOf("\\") >= 0 ) {
                  file = new File( filePath + 
                  fileName.substring( fileName.lastIndexOf("\\"))) ;
               } else {
                  file = new File( filePath + 
                  fileName.substring(fileName.lastIndexOf("\\")+1)) ;
               }
               fi.write( file ) ;
               out.println("Uploaded Filename: " + filePath + 
               fileName + "<br>");
            }
         }
         out.println("</body>");
         out.println("</html>");
      } catch(Exception ex) {
         System.out.println(ex);
      }
   } else {
      out.println("<html>");
      out.println("<head>");
      out.println("<title>Servlet upload</title>");  
      out.println("</head>");
      out.println("<body>");
      out.println("<p>No file uploaded</p>"); 
      out.println("</body>");
      out.println("</html>");
   }
%>

现在尝试使用上面创建的 HTML 表单上传文件。当您尝试 **https://127.0.0.1:8080/UploadFile.htm** 时,它将显示以下结果。这将帮助您从本地机器上传任何文件。

File Upload

Select a file to upload −


如果您的 JSP 脚本运行良好,则您的文件应上传到 **c:\apache-tomcat5.5.29\webapps\data\** 目录。

JSP - 处理日期

在本节中,我们将讨论如何在 JSP 中处理数据。使用 JSP 的最重要的优势之一是您可以使用核心 Java 中的所有可用方法。我们将向您介绍 **java.util** 包中提供的 **Date** 类;此类封装了当前日期和时间。

Date 类支持两个构造函数。第一个构造函数使用当前日期和时间初始化对象。

Date( )

以下构造函数接受一个参数,该参数等于自 1970 年 1 月 1 日午夜以来的毫秒数。

Date(long millisec)

一旦您拥有一个 Date 对象,您就可以调用以下任何支持方法来处理日期:

序号 方法和描述
1

boolean after(Date date)

如果调用 Date 对象包含的日期晚于 date 指定的日期,则返回 true,否则返回 false。

2

boolean before(Date date)

如果调用 Date 对象包含的日期早于 date 指定的日期,则返回 true,否则返回 false。

3

Object clone( )

复制调用 Date 对象。

4

int compareTo(Date date)

将调用对象的 value 与 date 的 value 进行比较。如果值相等,则返回 0。如果调用对象早于 date,则返回负值。如果调用对象晚于 date,则返回正值。

5

int compareTo(Object obj)

如果 obj 是 Date 类,则与 compareTo(Date) 的操作相同。否则,它将抛出 ClassCastException。

6

boolean equals(Object date)

如果调用 Date 对象包含与 date 指定的日期和时间相同的时间和日期,则返回 true,否则返回 false。

7

long getTime( )

返回自 1970 年 1 月 1 日以来的毫秒数。

8

int hashCode( )

返回调用对象的哈希码。

9

void setTime(long time)

设置由 time 指定的时间和日期,time 表示自 1970 年 1 月 1 日午夜以来的毫秒数

10

String toString( )

将调用 Date 对象转换为字符串并返回结果。

获取当前日期和时间

使用 JSP 程序,获取当前日期和时间非常容易。您可以使用带有 **toString()** 方法的简单 Date 对象来打印当前日期和时间,如下所示:

<%@ page import = "java.io.*,java.util.*, javax.servlet.*" %>

<html>
   <head>
      <title>Display Current Date & Time</title>
   </head>
   
   <body>
      <center>
         <h1>Display Current Date & Time</h1>
      </center>
      <%
         Date date = new Date();
         out.print( "<h2 align = \"center\">" +date.toString()+"</h2>");
      %>
   </body>
</html>

现在让我们将代码保存在 **CurrentDate.jsp** 中,然后使用 URL **https://127.0.0.1:8080/CurrentDate.jsp** 调用此 JSP。您将收到以下结果:

Display Current Date & Time

Mon Jun 21 21:46:49 GMT+04:00 2010

使用 **URL https://127.0.0.1:8080/CurrentDate.jsp** 刷新页面。每次刷新时,您都会发现秒数不同。

日期比较

如前几节所述,您可以在 JSP 脚本中使用所有可用的 Java 方法。如果您需要比较两个日期,请考虑以下方法:

  • 您可以使用 **getTime( )** 方法获取两个对象自 1970 年 1 月 1 日午夜以来的毫秒数,然后比较这两个值。

  • 您可以使用 **before( ), after( )** 和 **equals( )** 方法,例如,因为月中的第 12 天早于第 18 天,所以 **new Date(99, 2, 12).before(new Date (99, 2, 18))** 返回 true。

  • 您可以使用 **compareTo( )** 方法;此方法由 **Comparable 接口** 定义并由 Date 实现。

使用 SimpleDateFormat 格式化日期

SimpleDateFormat 是一个用于以区域感知方式格式化和解析日期的具体类。SimpleDateFormat 允许您首先选择任何用户定义的日期时间格式模式。

让我们修改上面的示例,如下所示:

<%@ page import = "java.io.*,java.util.*" %>
<%@ page import = "javax.servlet.*,java.text.*" %>

<html>
   <head>
      <title>Display Current Date & Time</title>
   </head>
   
   <body>
      <center>
         <h1>Display Current Date & Time</h1>
      </center>
      <%
         Date dNow = new Date( );
         SimpleDateFormat ft = 
         new SimpleDateFormat ("E yyyy.MM.dd 'at' hh:mm:ss a zzz");
         out.print( "<h2 align=\"center\">" + ft.format(dNow) + "</h2>");
      %>
   </body>
</html>

再次编译以上 servlet,然后使用 URL **https://127.0.0.1:8080/CurrentDate** 调用此 servlet。您将收到以下结果:

Display Current Date & Time

Mon 2010.06.21 at 10:06:44 PM GMT+04:00

SimpleDateFormat 格式代码

要指定时间格式,请使用时间模式字符串。在此模式中,所有 ASCII 字母都保留为模式字母,其定义如下:

字符 描述 示例
G 时代指示符 公元
y 四位数年份 2001
M 月份 七月或 07
d 0
h 上午/下午小时(1~12) 2
H 一天中的小时(0~23) 22
m 分钟 30
s 55
S 毫秒 234
E 星期几 星期二
D 一年中的第几天 360
F 一个月中的第几个星期几 2(七月中的第二个星期三)
w 一年中的第几周 40
W 一个月中的第几周
a 上午/下午标记 下午
k 一天中的小时(1~24) 24
K 上午/下午小时(0~11) 0
z 时区 东部标准时间
' 转义文本 分隔符
" 单引号 `

有关可用于操作日期的完整常量方法列表,您可以参考标准 Java 文档。

JSP - 页面重定向

在本节中,我们将讨论使用JSP进行页面重定向。页面重定向通常用于文档移动到新位置,我们需要将客户端发送到此新位置。这可能是由于负载均衡或简单的随机化。

将请求重定向到另一个页面的最简单方法是使用响应对象的sendRedirect()方法。以下是此方法的签名:

public void response.sendRedirect(String location)
throws IOException 

此方法将响应连同状态代码和新页面位置一起发送回浏览器。您还可以将setStatus()setHeader()方法一起使用来实现相同的重定向示例:

....
String site = "http://www.newpage.com" ;
response.setStatus(response.SC_MOVED_TEMPORARILY);
response.setHeader("Location", site); 
....

示例

此示例显示JSP如何执行到另一个位置的页面重定向:

<%@ page import = "java.io.*,java.util.*" %>

<html>
   <head>
      <title>Page Redirection</title>
   </head>
   
   <body>
      <center>
         <h1>Page Redirection</h1>
      </center>
      <%
         // New location to be redirected
         String site = new String("http://www.photofuntoos.com");
         response.setStatus(response.SC_MOVED_TEMPORARILY);
         response.setHeader("Location", site); 
      %>
   </body>
</html>

现在,我们将以上代码放入PageRedirect.jsp中,并使用URLhttps://127.0.0.1:8080/PageRedirect.jsp调用此JSP。这将带您到给定的URLhttp://www.photofuntoos.com

JSP - 访问计数器

在本节中,我们将讨论JSP中的访问计数器。访问计数器会告诉您网站特定页面上的访问次数。通常,您将访问计数器与index.jsp页面关联,假设人们首先访问您的主页。

要实现访问计数器,您可以使用Application隐式对象以及关联的方法getAttribute()setAttribute()

此对象在其整个生命周期中表示JSP页面。此对象在JSP页面初始化时创建,并在JSP页面被jspDestroy()方法移除时移除。

以下是设置应用程序级别变量的语法:

application.setAttribute(String Key, Object Value);

您可以使用上述方法设置访问计数器变量并重置相同的变量。以下是读取先前方法设置的变量的方法:

application.getAttribute(String Key);

每次用户访问您的页面时,您可以读取访问计数器的当前值,将其增加 1,然后再次将其设置为供将来使用。

示例

此示例显示如何使用JSP计算特定页面的总访问次数。如果要计算网站的总访问次数,则必须在所有JSP页面中包含相同的代码。

<%@ page import = "java.io.*,java.util.*" %>

<html>
   <head>
      <title>Application object in JSP</title>
   </head>
   
   <body>
      <%
         Integer hitsCount = (Integer)application.getAttribute("hitCounter");
         if( hitsCount ==null || hitsCount == 0 ) {
            /* First visit */
            out.println("Welcome to my website!");
            hitsCount = 1;
         } else {
            /* return visit */
            out.println("Welcome back to my website!");
            hitsCount += 1;
         }
         application.setAttribute("hitCounter", hitsCount);
      %>
      <center>
         <p>Total number of visits: <%= hitsCount%></p>
      </center>
   
   </body>
</html>

现在,我们将以上代码放入main.jsp中,并使用URLhttps://127.0.0.1:8080/main.jsp调用此JSP。这将显示访问计数器值,该值在您刷新页面时会增加。您可以尝试使用不同的浏览器访问页面,您会发现访问计数器将随着每次访问而不断增加,并且您将收到如下结果:

Welcome back to my website!

Total number of visits: 12

访问计数器重置

当您重新启动应用程序(即Web服务器)时会发生什么?这将重置您的应用程序变量,并且您的计数器将重置为零。为了避免此损失,请考虑以下几点:

  • 定义一个包含单个计数的数据库表,例如hitcount。为其分配零值。

  • 每次访问时,读取表以获取hitcount的值。

  • 将hitcount的值增加 1,并使用新值更新表。

  • 将hitcount的新值显示为总页面访问次数。

  • 如果要计算所有页面的访问次数,请为所有页面实现上述逻辑。

JSP - 自动刷新

在本节中,我们将讨论JSP中的自动刷新。考虑一个显示实时游戏比分或股市状态或货币汇率的网页。对于所有此类页面,您需要定期使用浏览器的刷新或重新加载按钮刷新网页。

JSP 通过提供一种机制使这项工作变得容易,您可以通过这种机制创建网页,以便在给定的时间间隔后自动刷新。

刷新网页的最简单方法是使用响应对象的setIntHeader()方法。以下是此方法的签名:

public void setIntHeader(String header, int headerValue)

此方法将标头“Refresh”连同表示以秒为单位的时间间隔的整数值一起发送回浏览器。

自动页面刷新示例

在以下示例中,我们将使用setIntHeader()方法设置Refresh标头。这将有助于模拟数字时钟:

<%@ page import = "java.io.*,java.util.*" %>

<html>
   <head>
      <title>Auto Refresh Header Example</title>
   </head>
   
   <body>
      <center>
         <h2>Auto Refresh Header Example</h2>
         <%
            // Set refresh, autoload time as 5 seconds
            response.setIntHeader("Refresh", 5);
            
            // Get current time
            Calendar calendar = new GregorianCalendar();
            String am_pm;
            
            int hour = calendar.get(Calendar.HOUR);
            int minute = calendar.get(Calendar.MINUTE);
            int second = calendar.get(Calendar.SECOND);
            
            if(calendar.get(Calendar.AM_PM) == 0)
               am_pm = "AM";
            else
               am_pm = "PM";
            String CT = hour+":"+ minute +":"+ second +" "+ am_pm;
            out.println("Crrent Time: " + CT + "\n");
         %>
      </center>
   
   </body>
</html>

现在将以上代码放入main.jsp中并尝试访问它。这将在每 5 秒后显示当前系统时间,如下所示。只需运行JSP并等待查看结果:

Auto Refresh Header Example

Current Time is: 9:44:50 PM

JSP - 发送邮件

在本节中,我们将讨论如何使用JSP发送电子邮件。要使用JSP发送电子邮件,您应该在您的计算机上安装JavaMail APIJava Activation Framework (JAF)

下载并解压缩这些文件,在新建的顶级目录中。您会发现这两个应用程序都有许多jar文件。您需要将mail.jaractivation.jar文件添加到您的CLASSPATH中。

发送简单的电子邮件

这是一个从您的计算机发送简单电子邮件的示例。假设您的localhost已连接到Internet,并且能够发送电子邮件。确保Java Email API包和JAF包中的所有jar文件都存在于CLASSPATH中。

<%@ page import = "java.io.*,java.util.*,javax.mail.*"%>
<%@ page import = "javax.mail.internet.*,javax.activation.*"%>
<%@ page import = "javax.servlet.http.*,javax.servlet.*" %>

<%
   String result;
   
   // Recipient's email ID needs to be mentioned.
   String to = "[email protected]";

   // Sender's email ID needs to be mentioned
   String from = "[email protected]";

   // Assuming you are sending email from localhost
   String host = "localhost";

   // Get system properties object
   Properties properties = System.getProperties();

   // Setup mail server
   properties.setProperty("mail.smtp.host", host);

   // Get the default Session object.
   Session mailSession = Session.getDefaultInstance(properties);

   try {
      // Create a default MimeMessage object.
      MimeMessage message = new MimeMessage(mailSession);
      
      // Set From: header field of the header.
      message.setFrom(new InternetAddress(from));
      
      // Set To: header field of the header.
      message.addRecipient(Message.RecipientType.TO,
                               new InternetAddress(to));
      // Set Subject: header field
      message.setSubject("This is the Subject Line!");
      
      // Now set the actual message
      message.setText("This is actual message");
      
      // Send message
      Transport.send(message);
      result = "Sent message successfully....";
   } catch (MessagingException mex) {
      mex.printStackTrace();
      result = "Error: unable to send message....";
   }
%>

<html>
   <head>
      <title>Send Email using JSP</title>
   </head>
   
   <body>
      <center>
         <h1>Send Email using JSP</h1>
      </center>
      
      <p align = "center">
         <% 
            out.println("Result: " + result + "\n");
         %>
      </p>
   </body>
</html>

现在,我们将以上代码放入SendEmail.jsp文件中,并使用URLhttps://127.0.0.1:8080/SendEmail.jsp调用此JSP。这将有助于将电子邮件发送到给定的电子邮件ID[email protected]。您将收到以下回复:

Send Email using JSP

Result: Sent message successfully....

如果要将电子邮件发送给多个收件人,则可以使用以下方法指定多个电子邮件ID:

void addRecipients(Message.RecipientType type, Address[] addresses)
throws MessagingException

以下是参数的描述:

  • type - 这将设置为TO、CC或BCC。此处CC表示抄送,BCC表示密件抄送。例如Message.RecipientType.TO

  • addresses - 这是电子邮件ID的数组。在指定电子邮件ID时,您需要使用InternetAddress()方法

发送HTML电子邮件

这是一个从您的计算机发送HTML电子邮件的示例。假设您的localhost已连接到Internet,并且能够发送电子邮件。确保Java Email API包和JAF包中的所有jar文件都存在于CLASSPATH中。

此示例与前一个示例非常相似,只是在这里我们使用setContent()方法设置内容,其第二个参数为“text/html”以指定邮件中包含HTML内容。

使用此示例,您可以发送任意大小的HTML内容。

<%@ page import = "java.io.*,java.util.*,javax.mail.*"%>
<%@ page import = "javax.mail.internet.*,javax.activation.*"%>
<%@ page import = "javax.servlet.http.*,javax.servlet.*" %>

<%
   String result;
   
   // Recipient's email ID needs to be mentioned.
   String to = "[email protected]";

   // Sender's email ID needs to be mentioned
   String from = "[email protected]";

   // Assuming you are sending email from localhost
   String host = "localhost";

   // Get system properties object
   Properties properties = System.getProperties();

   // Setup mail server
   properties.setProperty("mail.smtp.host", host);

   // Get the default Session object.
   Session mailSession = Session.getDefaultInstance(properties);

   try {
      // Create a default MimeMessage object.
      MimeMessage message = new MimeMessage(mailSession);
      
      // Set From: header field of the header.
      message.setFrom(new InternetAddress(from));
      
      // Set To: header field of the header.
      message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
      
      // Set Subject: header field
      message.setSubject("This is the Subject Line!");
     
      // Send the actual HTML message, as big as you like
      message.setContent("<h1>This is actual message</h1>", "text/html" );
      
      // Send message
      Transport.send(message);
      result = "Sent message successfully....";
   } catch (MessagingException mex) {
      mex.printStackTrace();
      result = "Error: unable to send message....";
   }
%>

<html>
   <head>
      <title>Send HTML Email using JSP</title>
   </head>

   <body>
      <center>
         <h1>Send Email using JSP</h1>
      </center>
      
      <p align = "center">
         <% 
            out.println("Result: " + result + "\n");
         %>
      </p>
   </body>
</html>

现在,让我们使用以上JSP将HTML邮件发送到给定的电子邮件ID。

在电子邮件中发送附件

以下是从您的计算机发送包含附件的电子邮件的示例:

<%@ page import = "java.io.*,java.util.*,javax.mail.*"%>
<%@ page import = "javax.mail.internet.*,javax.activation.*"%>
<%@ page import = "javax.servlet.http.*,javax.servlet.*" %>

<%
   String result;
   
   // Recipient's email ID needs to be mentioned.
   String to = "[email protected]";

   // Sender's email ID needs to be mentioned
   String from = "[email protected]";

   // Assuming you are sending email from localhost
   String host = "localhost";

   // Get system properties object
   Properties properties = System.getProperties();

   // Setup mail server
   properties.setProperty("mail.smtp.host", host);

   // Get the default Session object.
   Session mailSession = Session.getDefaultInstance(properties);

   try {
      // Create a default MimeMessage object.
      MimeMessage message = new MimeMessage(mailSession);

      // Set From: header field of the header.
      message.setFrom(new InternetAddress(from));

      // Set To: header field of the header.
      message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));

      // Set Subject: header field
      message.setSubject("This is the Subject Line!");

      // Create the message part 
      BodyPart messageBodyPart = new MimeBodyPart();

      // Fill the message
      messageBodyPart.setText("This is message body");
      
      // Create a multipart message
      Multipart multipart = new MimeMultipart();

      // Set text message part
      multipart.addBodyPart(messageBodyPart);

      // Part two is attachment
      messageBodyPart = new MimeBodyPart();
      
      String filename = "file.txt";
      DataSource source = new FileDataSource(filename);
      messageBodyPart.setDataHandler(new DataHandler(source));
      messageBodyPart.setFileName(filename);
      multipart.addBodyPart(messageBodyPart);

      // Send the complete message parts
      message.setContent(multipart );

      // Send message
      Transport.send(message);
      String title = "Send Email";
      result = "Sent message successfully....";
   } catch (MessagingException mex) {
      mex.printStackTrace();
      result = "Error: unable to send message....";
   }
%>

<html>
   <head>
      <title>Send Attachment Email using JSP</title>
   </head>
   
   <body>
      <center>
         <h1>Send Attachment Email using JSP</h1>
      </center>
      
      <p align = "center">
         <%out.println("Result: " + result + "\n");%>
      </p>
   </body>
</html>

现在,让我们运行以上JSP,将文件作为附件连同邮件一起发送到给定的电子邮件ID。

用户身份验证部分

如果需要向电子邮件服务器提供用户ID和密码以进行身份验证,则可以按如下方式设置这些属性:

props.setProperty("mail.user", "myuser");
props.setProperty("mail.password", "mypwd");

其余的电子邮件发送机制将保持如上所述。

使用表单发送电子邮件

您可以使用HTML表单接受电子邮件参数,然后您可以使用request对象获取所有信息,如下所示:

String to = request.getParameter("to");
String from = request.getParameter("from");
String subject = request.getParameter("subject");
String messageText = request.getParameter("body");

获取所有信息后,您可以使用上述程序发送电子邮件。

JSP - 标准标签库 (JSTL) 教程

在本节中,我们将了解JSP中的不同标签。JavaServer Pages Standard Tag Library (JSTL) 是一个有用的JSP标签集合,它封装了许多JSP应用程序共有的核心功能。

JSTL 支持常见的结构化任务,例如迭代和条件语句,用于操作XML文档的标签、国际化标签和SQL标签。它还提供了一个框架,用于将现有的自定义标签与JSTL标签集成。

安装JSTL库

要开始使用JSP标签,您需要首先安装JSTL库。如果您使用的是Apache Tomcat容器,则请按照以下两个步骤操作:

步骤 1 - 从Apache Standard Taglib下载二进制发行版并解压缩压缩文件。

步骤 2 - 要从其Jakarta Taglibs发行版中使用Standard Taglib,只需将发行版“lib”目录中的JAR文件复制到应用程序的webapps\ROOT\WEB-INF\lib目录中即可。

要使用任何库,您必须在使用该库的每个JSP顶部包含一个<taglib>指令。

JSTL标签的分类

根据其功能,JSTL标签可以分为以下JSTL标签库组,这些组可用于创建JSP页面:

  • 核心标签

  • 格式化标签

  • SQL标签

  • XML标签

  • JSTL函数

核心标签

核心标签组是最常用的JSTL标签。以下是将JSTL核心库包含在您的JSP中的语法:

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

下表列出了核心JSTL标签:

序号 标签 & 描述
1 <c:out>

类似于<%= ... >,但用于表达式。

2 <c:set >

'scope'中设置表达式计算的结果

3 <c:remove >

移除作用域变量(如果指定,则从特定作用域中移除)。

4 <c:catch>

捕获其主体中发生的任何Throwable,并可以选择性地公开它。

5 <c:if>

简单的条件标签,如果提供的条件为真,则计算其主体。

6 <c:choose>

简单的条件标签,它为相互排斥的条件操作建立上下文,由<when><otherwise>标记。

7 <c:when>

<choose>的子标签,如果其条件计算结果为'true',则包含其主体。

8 <c:otherwise >

<choose>的子标签,位于<when>标签之后,仅当所有先前的条件计算结果为'false'时才运行。

9 <c:import>

检索绝对或相对URL,并将内容公开到页面、'var'中的字符串或'varReader'中的Reader。

10 <c:forEach >

基本的迭代标签,接受许多不同的集合类型并支持子集和其他功能。

11 <c:forTokens>

遍历由提供的分隔符分隔的标记。

12 <c:param>

向包含的'import'标签的URL添加参数。

13 <c:redirect >

重定向到新的URL。

14 <c:url>

创建带可选查询参数的URL

格式化标签

JSTL格式化标签用于格式化和显示文本、日期、时间和国际化网站的数字。以下是将格式化库包含在您的JSP中的语法:

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

下表列出了格式化JSTL标签:

序号 标签 & 描述
1 <fmt:formatNumber>

以特定精度或格式呈现数值。

2 <fmt:parseNumber>

分析数字、货币或百分比的字符串表示形式。

3 <fmt:formatDate>

使用提供的样式和模式格式化日期和/或时间。

4 <fmt:parseDate>

分析日期和/或时间的字符串表示形式

5 <fmt:bundle>

加载其标签主体将使用的资源包。

6 <fmt:setLocale>

将给定的区域设置存储在区域设置配置变量中。

7 <fmt:setBundle>

加载资源包并将其存储在命名的作用域变量或 bundle 配置变量中。

8 <fmt:timeZone>

指定其主体中嵌套的任何时间格式化或解析操作的时间区域。

9 <fmt:setTimeZone>

将给定的时区存储在时区配置变量中

10 <fmt:message>

显示国际化消息。

11 <fmt:requestEncoding>

设置请求字符编码

SQL标签

JSTL SQL 标签库提供用于与关系数据库 (RDBMS) 交互的标签,例如Oracle、mySQLMicrosoft SQL Server

以下是将 JSTL SQL 库包含在 JSP 中的语法:

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

下表列出了 SQL JSTL 标签:

序号 标签 & 描述
1 <sql:setDataSource>

创建一个仅适用于原型设计的简单 DataSource

2 <sql:query>

执行其主体中或通过 sql 属性定义的 SQL 查询。

3 <sql:update>

执行其主体中或通过 sql 属性定义的 SQL 更新。

4 <sql:param>

将 SQL 语句中的参数设置为指定值。

5 <sql:dateParam>

将 SQL 语句中的参数设置为指定的 java.util.Date 值。

6 <sql:transaction >

为嵌套的数据库操作元素提供共享的 Connection,设置为将所有语句作为一个事务执行。

XML标签

JSTL XML 标签提供了一种以 JSP 为中心的创建和操作 XML 文档的方法。以下是将 JSTL XML 库包含在 JSP 中的语法。

JSTL XML 标签库具有用于与 XML 数据交互的自定义标签。这包括解析 XML、转换 XML 数据以及基于 XPath 表达式的流程控制。

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

在继续示例之前,您需要将以下两个与 XML 和 XPath 相关的库复制到您的<Tomcat 安装目录>\lib中:

以下是 XML JSTL 标签的列表:

序号 标签 & 描述
1 <x:out>

类似于<%= ... >,但用于 XPath 表达式。

2 <x:parse>

用于解析通过属性或标签主体指定的 XML 数据。

3 <x:set >

将变量设置为 XPath 表达式的值。

4 <x:if >

评估测试 XPath 表达式,如果为真,则处理其主体。如果测试条件为假,则忽略主体。

5 <x:forEach>

循环遍历 XML 文档中的节点。

6 <x:choose>

简单的条件标签,为相互排斥的条件操作建立上下文,由<when><otherwise>标签标记。

7 <x:when >

<choose>的子标签,如果其表达式计算结果为“true”,则包含其主体。

8 <x:otherwise >

<choose>的子标签,位于<when>标签之后,仅当所有先前条件计算结果为“false”时才运行。

9 <x:transform >

对 XML 文档应用 XSL 转换

10 <x:param >

transform标签一起使用,以在 XSLT 样式表中设置参数

JSTL函数

JSTL 包含许多标准函数,其中大多数是常见的字符串操作函数。以下是将 JSTL 函数库包含在 JSP 中的语法:

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

下表列出了各种 JSTL 函数:

序号 函数 & 描述
1 fn:contains()

测试输入字符串是否包含指定的子字符串。

2 fn:containsIgnoreCase()

不区分大小写地测试输入字符串是否包含指定的子字符串。

3 fn:endsWith()

测试输入字符串是否以指定的后缀结尾。

4 fn:escapeXml()

转义可以解释为 XML 标记的字符。

5 fn:indexOf()

返回字符串中指定子字符串首次出现的索引。

6 fn:join()

将数组的所有元素连接成一个字符串。

7 fn:length()

返回集合中的项目数或字符串中的字符数。

8 fn:replace()

返回一个字符串,该字符串是通过替换输入字符串中所有出现的给定字符串而生成的。

9 fn:split()

将字符串拆分为子字符串数组。

10 fn:startsWith()

测试输入字符串是否以指定的前缀开头。

11 fn:substring()

返回字符串的子集。

12 fn:substringAfter()

返回特定子字符串之后字符串的子集。

13 fn:substringBefore()

返回特定子字符串之前字符串的子集。

14 fn:toLowerCase()

将字符串的所有字符转换为小写。

15 fn:toUpperCase()

将字符串的所有字符转换为大写。

16 fn:trim()

删除字符串两端的白空格。

JSP - 数据库访问

在本章中,我们将讨论如何使用 JSP 访问数据库。我们假设您对 JDBC 应用程序的工作原理有很好的了解。在通过 JSP 开始访问数据库之前,请确保您已正确设置 JDBC 环境以及数据库。

有关如何使用 JDBC 访问数据库及其环境设置的更多详细信息,您可以查看我们的JDBC 教程

为了开始了解基本概念,让我们创建一个表并在该表中创建一些记录,如下所示:

创建表

要创建 EMP 数据库中的Employees表,请使用以下步骤:

步骤 1

打开命令提示符并更改到安装目录,如下所示:

C:\>
C:\>cd Program Files\MySQL\bin
C:\Program Files\MySQL\bin>

步骤 2

登录到数据库,如下所示:

C:\Program Files\MySQL\bin>mysql -u root -p
Enter password: ********
mysql>

步骤 3

TEST数据库中创建Employee表,如下所示:

mysql> use TEST;
mysql> create table Employees
   (
      id int not null,
      age int not null,
      first varchar (255),
      last varchar (255)
   );
Query OK, 0 rows affected (0.08 sec)
mysql>

创建数据记录

现在让我们在Employee表中创建一些记录,如下所示:

mysql> INSERT INTO Employees VALUES (100, 18, 'Zara', 'Ali');
Query OK, 1 row affected (0.05 sec)
 
mysql> INSERT INTO Employees VALUES (101, 25, 'Mahnaz', 'Fatma');
Query OK, 1 row affected (0.00 sec)
 
mysql> INSERT INTO Employees VALUES (102, 30, 'Zaid', 'Khan');
Query OK, 1 row affected (0.00 sec)
 
mysql> INSERT INTO Employees VALUES (103, 28, 'Sumit', 'Mittal');
Query OK, 1 row affected (0.00 sec)
 
mysql>

SELECT 操作

以下示例显示了如何在 JSP 编程中使用 JTSL 执行SQL SELECT语句:

<%@ page import = "java.io.*,java.util.*,java.sql.*"%>
<%@ page import = "javax.servlet.http.*,javax.servlet.*" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix = "c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix = "sql"%>
 
<html>
   <head>
      <title>SELECT Operation</title>
   </head>

   <body>
      <sql:setDataSource var = "snapshot" driver = "com.mysql.jdbc.Driver"
         url = "jdbc:mysql://127.0.0.1/TEST"
         user = "root"  password = "pass123"/>
 
      <sql:query dataSource = "${snapshot}" var = "result">
         SELECT * from Employees;
      </sql:query>
 
      <table border = "1" width = "100%">
         <tr>
            <th>Emp ID</th>
            <th>First Name</th>
            <th>Last Name</th>
            <th>Age</th>
         </tr>
         
         <c:forEach var = "row" items = "${result.rows}">
            <tr>
               <td><c:out value = "${row.id}"/></td>
               <td><c:out value = "${row.first}"/></td>
               <td><c:out value = "${row.last}"/></td>
               <td><c:out value = "${row.age}"/></td>
            </tr>
         </c:forEach>
      </table>
 
   </body>
</html>

访问上述 JSP,将显示以下结果:

Emp ID First Name Last Name Age
100 Zara Ali 18
101 Mahnaz Fatma 25
102 Zaid Khan 30
103 Sumit Mittal 28

INSERT 操作

以下示例显示了如何在 JSP 编程中使用 JTSL 执行 SQL INSERT 语句:

<%@ page import = "java.io.*,java.util.*,java.sql.*"%>
<%@ page import = "javax.servlet.http.*,javax.servlet.*" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix = "c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix = "sql"%>
 
<html>
   <head>
      <title>JINSERT Operation</title>
   </head>
   
   <body>
      <sql:setDataSource var = "snapshot" driver = "com.mysql.jdbc.Driver"
         url = "jdbc:mysql://127.0.0.1/TEST"
         user = "root"  password = "pass123"/>
         <sql:update dataSource = "${snapshot}" var = "result">
         INSERT INTO Employees VALUES (104, 2, 'Nuha', 'Ali');
      </sql:update>
 
      <sql:query dataSource = "${snapshot}" var = "result">
         SELECT * from Employees;
      </sql:query>
 
      <table border = "1" width = "100%">
         <tr>
            <th>Emp ID</th>
            <th>First Name</th>
            <th>Last Name</th>
            <th>Age</th>
         </tr>
         
         <c:forEach var = "row" items = "${result.rows}">
            <tr>
               <td><c:out value = "${row.id}"/></td>
               <td><c:out value = "${row.first}"/></td>
               <td><c:out value = "${row.last}"/></td>
               <td><c:out value = "${row.age}"/></td>
            </tr>
         </c:forEach>
      </table>
 
   </body>
</html>

访问上述 JSP,将显示以下结果:

Emp ID First Name Last Name Age
100 Zara Ali 18
101 Mahnaz Fatma 25
102 Zaid Khan 30
103 Sumit Mittal 28
104 Nuha Ali 2

DELETE 操作

以下示例显示了如何在 JSP 编程中使用 JTSL 执行SQL DELETE语句:

<%@ page import = "java.io.*,java.util.*,java.sql.*"%>
<%@ page import = "javax.servlet.http.*,javax.servlet.*" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix = "c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix = "sql"%>
 
<html>
   <head>
      <title>DELETE Operation</title>
   </head>
   
   <body>
      <sql:setDataSource var = "snapshot" driver = "com.mysql.jdbc.Driver"
         url = "jdbc:mysql://127.0.0.1/TEST"
         user = "root" password = "pass123"/>
 
      <c:set var = "empId" value = "103"/>
 
      <sql:update dataSource = "${snapshot}" var = "count">
         DELETE FROM Employees WHERE Id = ?
         <sql:param value = "${empId}" />
      </sql:update>
 
      <sql:query dataSource = "${snapshot}" var = "result">
         SELECT * from Employees;
      </sql:query>
 
      <table border = "1" width = "100%">
         <tr>
            <th>Emp ID</th>
            <th>First Name</th>
            <th>Last Name</th>
            <th>Age</th>
         </tr>
            
         <c:forEach var = "row" items = "${result.rows}">
            <tr>
               <td><c:out value = "${row.id}"/></td>
               <td><c:out value = "${row.first}"/></td>
               <td><c:out value = "${row.last}"/></td>
               <td><c:out value = "${row.age}"/></td>
            </tr>
         </c:forEach>
      </table>
 
   </body>
</html>

访问上述 JSP,将显示以下结果:

Emp ID First Name Last Name Age
100 Zara Ali 18
101 Mahnaz Fatma 25
102 Zaid Khan 30

UPDATE 操作

以下示例显示了如何在 JSP 编程中使用 JTSL 执行SQL UPDATE语句:

<%@ page import = "java.io.*,java.util.*,java.sql.*"%>
<%@ page import = "javax.servlet.http.*,javax.servlet.*" %>
<%@ taglib uri = "http://java.sun.com/jsp/jstl/core" prefix = "c"%>
<%@ taglib uri = "http://java.sun.com/jsp/jstl/sql" prefix = "sql"%>
 
<html>
   <head>
      <title>DELETE Operation</title>
   </head>
   
   <body>
      <sql:setDataSource var = "snapshot" driver = "com.mysql.jdbc.Driver"
         url = "jdbc:mysql://127.0.0.1/TEST"
         user = "root" password = "pass123"/>
 
      <c:set var = "empId" value = "102"/>
 
      <sql:update dataSource = "${snapshot}" var = "count">
         UPDATE Employees SET WHERE last = 'Ali'
         <sql:param value = "${empId}" />
      </sql:update>
 
      <sql:query dataSource = "${snapshot}" var = "result">
         SELECT * from Employees;
      </sql:query>
 
      <table border = "1" width = "100%">
         <tr>
            <th>Emp ID</th>
            <th>First Name</th>
            <th>Last Name</th>
            <th>Age</th>
         </tr>
            
         <c:forEach var = "row" items = "${result.rows}">
            <tr>
               <td><c:out value = "${row.id}"/></td>
               <td><c:out value = "${row.first}"/></td>
               <td><c:out value = "${row.last}"/></td>
               <td><c:out value = "${row.age}"/></td>
            </tr>
         </c:forEach>
      </table>
 
   </body>
</html>

访问上述 JSP,将显示以下结果:

Emp ID First Name Last Name Age
100 Zara Ali 18
101 Mahnaz Fatma 25
102 Zaid Ali 30

JSP - XML 数据

当您通过 HTTP 发送 XML 数据时,使用 JSP 处理传入和传出 XML 文档是有意义的;例如,RSS 文档。由于 XML 文档仅仅是一堆文本,因此通过 JSP 创建一个 XML 文档比创建 HTML 文档容易得多。

从 JSP 发送 XML

您可以使用 JSP 以与发送 HTML 相同的方式发送 XML 内容。唯一的区别是您必须将页面的内容类型设置为 text/xml。要设置内容类型,请使用<%@page%>标签,如下所示:

<%@ page contentType = "text/xml" %>

以下示例将显示如何将 XML 内容发送到浏览器:

<%@ page contentType = "text/xml" %>

<books>
   <book>
      <name>Padam History</name>
      <author>ZARA</author>
      <price>100</price>
   </book>
</books>

使用不同的浏览器访问上述 XML 以查看上述 XML 的文档树表示。

在 JSP 中处理 XML

在继续使用 JSP 处理 XML 之前,您需要将以下两个与 XML 和 XPath 相关的库复制到您的<Tomcat 安装目录>\lib中:

让我们将以下内容放入 books.xml 文件中:

<books>
   <book>
      <name>Padam History</name>
      <author>ZARA</author>
      <price>100</price>
   </book>
   
   <book>
      <name>Great Mistry</name>
      <author>NUHA</author>
      <price>2000</price>
   </book>
</books>

尝试以下main.jsp,保留在同一目录中:

<%@ taglib prefix = "c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix = "x" uri="http://java.sun.com/jsp/jstl/xml" %>
 
<html>
   <head>
      <title>JSTL x:parse Tags</title>
   </head>

   <body>
      <h3>Books Info:</h3>
      <c:import var = "bookInfo" url="https://127.0.0.1:8080/books.xml"/>
 
      <x:parse xml = "${bookInfo}" var = "output"/>
      <b>The title of the first book is</b>: 
      <x:out select = "$output/books/book[1]/name" />
      <br>
      
      <b>The price of the second book</b>: 
      <x:out select = "$output/books/book[2]/price" />
   </body>
</html>

使用https://127.0.0.1:8080/main.jsp访问上述 JSP,将显示以下结果:

Books Info:

The title of the first book is:Padam History The price of the second book: 2000

使用 JSP 格式化 XML

考虑以下 XSLT 样式表style.xsl

<?xml version = "1.0"?>
<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" 
   version = "1.0">
 
   <xsl:output method = "html" indent = "yes"/>
   <xsl:template match = "/">
      <html>
         <body>
            <xsl:apply-templates/>
         </body>
      </html>
   </xsl:template>
    
   <xsl:template match = "books">
      <table border = "1" width = "100%">
         <xsl:for-each select = "book">
            <tr>
               <td>
                  <i><xsl:value-of select = "name"/></i>
               </td>
               
               <td>
                  <xsl:value-of select = "author"/>
               </td>
               
               <td>
                  <xsl:value-of select = "price"/>
               </td>
            </tr>
         </xsl:for-each>
      </table>
   
   </xsl:template>
</xsl:stylesheet>

现在考虑以下 JSP 文件:

<%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix = "x" uri = "http://java.sun.com/jsp/jstl/xml" %>
 
<html>
   <head>
      <title>JSTL x:transform Tags</title>
   </head>
   
   <body>
      <h3>Books Info:</h3>
      <c:set var = "xmltext">
         <books>
            <book>
               <name>Padam History</name>
               <author>ZARA</author>
               <price>100</price>
            </book>
            
            <book>
               <name>Great Mistry</name>
               <author>NUHA</author>
               <price>2000</price>
            </book>
         </books>
      </c:set>
 
      <c:import url = "https://127.0.0.1:8080/style.xsl" var = "xslt"/>
      <x:transform xml = "${xmltext}" xslt = "${xslt}"/>
   </body>
</html>

将显示以下结果:

Books Info:

Padam History ZARA 100
Great Mistry NUHA 2000

要了解有关使用 JSTL 处理 XML 的更多信息,您可以查看JSP 标准标签库

JSP - JavaBeans

JavaBean 是一个用 Java 编写的特殊构造的 Java 类,并根据 JavaBeans API 规范进行编码。

以下是将 JavaBean 与其他 Java 类区分开来的独特特征:

  • 它提供一个默认的无参数构造函数。

  • 它应该是可序列化的,并且可以实现Serializable接口。

  • 它可能具有一些可以读取或写入的属性。

  • 它可能具有一些用于属性的“getter”和“setter”方法。

JavaBeans 属性

JavaBean 属性是可以由对象用户访问的命名属性。属性可以是任何 Java 数据类型,包括您定义的类。

JavaBean 属性可以是只读、可写、只读只写。通过 JavaBean 实现类中的两种方法访问 JavaBean 属性:

序号 方法及描述
1

getPropertyName()

例如,如果属性名称为firstName,则您的方法名称将为getFirstName()以读取该属性。此方法称为访问器。

2

setPropertyName()

例如,如果属性名称为firstName,则您的方法名称将为setFirstName()以写入该属性。此方法称为修改器。

只读属性将仅具有getPropertyName()方法,而只写属性将仅具有setPropertyName()方法。

JavaBeans 示例

考虑一个具有少量属性的学生类:

package com.tutorialspoint;

public class StudentsBean implements java.io.Serializable {
   private String firstName = null;
   private String lastName = null;
   private int age = 0;

   public StudentsBean() {
   }
   public String getFirstName(){
      return firstName;
   }
   public String getLastName(){
      return lastName;
   }
   public int getAge(){
      return age;
   }
   public void setFirstName(String firstName){
      this.firstName = firstName;
   }
   public void setLastName(String lastName){
      this.lastName = lastName;
   }
   public void setAge(Integer age){
      this.age = age;
   }
}

访问 JavaBeans

useBean操作声明一个 JavaBean 以在 JSP 中使用。声明后,bean 成为一个脚本变量,既可以被 JSP 中使用的脚本元素访问,也可以被其他自定义标签访问。useBean标签的完整语法如下:

<jsp:useBean id = "bean's name" scope = "bean's scope" typeSpec/>

这里,scope 属性的值可以是page、request、sessionapplication,具体取决于您的需求。id属性的值可以是任何值,只要它在同一 JSP 中的其他useBean 声明中是唯一的名称即可。

以下示例显示了如何使用 useBean 操作:

<html>
   <head>
      <title>useBean Example</title>
   </head>
   
   <body>
      <jsp:useBean id = "date" class = "java.util.Date" /> 
      <p>The date/time is <%= date %>
   </body>
</html>

您将收到以下结果:

The date/time is Thu Sep 30 11:18:11 GST 2010 

访问 JavaBeans 属性

除了<jsp:useBean...>操作之外,您还可以使用<jsp:getProperty/>操作访问 get 方法,并使用<jsp:setProperty/>操作访问 set 方法。以下是完整语法:

<jsp:useBean id = "id" class = "bean's class" scope = "bean's scope">
   <jsp:setProperty name = "bean's id" property = "property name"  
      value = "value"/>
   <jsp:getProperty name = "bean's id" property = "property name"/>
   ...........
</jsp:useBean>

name 属性引用先前由 useBean 操作引入 JSP 的 JavaBean 的 id。property 属性是要调用的getset方法的名称。

以下示例显示了如何使用上述语法访问数据:

<html>
   <head>
      <title>get and set properties Example</title>
   </head>
   
   <body>
      <jsp:useBean id = "students" class = "com.tutorialspoint.StudentsBean"> 
         <jsp:setProperty name = "students" property = "firstName" value = "Zara"/>
         <jsp:setProperty name = "students" property = "lastName" value = "Ali"/>
         <jsp:setProperty name = "students" property = "age" value = "10"/>
      </jsp:useBean>

      <p>Student First Name: 
         <jsp:getProperty name = "students" property = "firstName"/>
      </p>
      
      <p>Student Last Name: 
         <jsp:getProperty name = "students" property = "lastName"/>
      </p>
      
      <p>Student Age: 
         <jsp:getProperty name = "students" property = "age"/>
      </p>

   </body>
</html>

让我们使StudentsBean.class在 CLASSPATH 中可用。访问上述 JSP,将显示以下结果:

Student First Name: Zara 

Student Last Name: Ali 

Student Age: 10 

JSP - 自定义标签

在本章中,我们将讨论 JSP 中的自定义标签。自定义标签是用户定义的 JSP 语言元素。当包含自定义标签的 JSP 页面转换为 servlet 时,该标签将转换为对称为标签处理器的对象的运算。然后,当执行 JSP 页面的 servlet 时,Web 容器将调用这些操作。

JSP 标签扩展允许您创建新的标签,您可以将其直接插入 JavaServer 页面。JSP 2.0 规范引入了用于编写这些自定义标签的简单标签处理器。

要编写自定义标签,您可以简单地扩展SimpleTagSupport类并覆盖doTag()方法,您可以在其中放置生成标签内容的代码。

创建“Hello”标签

假设您想定义一个名为<ex:Hello>的自定义标签,并且您想以以下方式在没有主体的情况下使用它:

<ex:Hello />

要创建自定义JSP标签,您必须首先创建一个充当标签处理程序的Java类。现在让我们创建如下所示的HelloTag类:

package com.tutorialspoint;

import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;

public class HelloTag extends SimpleTagSupport {
   public void doTag() throws JspException, IOException {
      JspWriter out = getJspContext().getOut();
      out.println("Hello Custom Tag!");
   }
}

以上代码包含简单的编码,其中doTag()方法使用getJspContext()方法获取当前的JspContext对象,并使用它将"Hello Custom Tag!"发送到当前的JspWriter对象。

让我们编译上述类并将其复制到环境变量CLASSPATH中可用的目录中。最后,创建以下标签库文件:<Tomcat-Installation-Directory>webapps\ROOT\WEB-INF\custom.tld

<taglib>
   <tlib-version>1.0</tlib-version>
   <jsp-version>2.0</jsp-version>
   <short-name>Example TLD</short-name>
   
   <tag>
      <name>Hello</name>
      <tag-class>com.tutorialspoint.HelloTag</tag-class>
      <body-content>empty</body-content>
   </tag>
</taglib>

现在让我们在JSP程序中使用上面定义的自定义标签Hello,如下所示:

<%@ taglib prefix = "ex" uri = "WEB-INF/custom.tld"%>

<html>
   <head>
      <title>A sample custom tag</title>
   </head>
   
   <body>
      <ex:Hello/>
   </body>
</html>

调用上述JSP,这应该会产生以下结果:

Hello Custom Tag!

访问标签体

您可以像在标准标签中看到的那样,在标签体中包含一条消息。假设您想定义一个名为<ex:Hello>的自定义标签,并且您想以以下方式在有主体的情况下使用它:

<ex:Hello>
   This is message body
</ex:Hello>

让我们对上述标签代码进行以下更改以处理标签体:

package com.tutorialspoint;

import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;

public class HelloTag extends SimpleTagSupport {
   StringWriter sw = new StringWriter();
   public void doTag()
   
   throws JspException, IOException {
      getJspBody().invoke(sw);
      getJspContext().getOut().println(sw.toString());
   }
}

在这里,调用产生的输出首先被捕获到StringWriter中,然后再写入与标签关联的JspWriter。我们需要如下更改TLD文件:

<taglib>
   <tlib-version>1.0</tlib-version>
   <jsp-version>2.0</jsp-version>
   <short-name>Example TLD with Body</short-name>
   
   <tag>
      <name>Hello</name>
      <tag-class>com.tutorialspoint.HelloTag</tag-class>
      <body-content>scriptless</body-content>
   </tag>
</taglib>

现在让我们以适当的主体调用上述标签,如下所示:

<%@ taglib prefix = "ex" uri = "WEB-INF/custom.tld"%>

<html>
   <head>
      <title>A sample custom tag</title>
   </head>
   
   <body>
      <ex:Hello>
         This is message body
      </ex:Hello>
   </body>
</html>

您将收到以下结果:

This is message body

自定义标签属性

您可以与自定义标签一起使用各种属性。要接受属性值,自定义标签类需要实现setter方法,与JavaBean setter方法相同,如下所示:

package com.tutorialspoint;

import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;

public class HelloTag extends SimpleTagSupport {
   private String message;

   public void setMessage(String msg) {
      this.message = msg;
   }
   StringWriter sw = new StringWriter();
   public void doTag()
   
   throws JspException, IOException {
      if (message != null) {
         /* Use message from attribute */
         JspWriter out = getJspContext().getOut();
         out.println( message );
      } else {
         /* use message from the body */
         getJspBody().invoke(sw);
         getJspContext().getOut().println(sw.toString());
      }
   }
}

属性的名称是"message",所以setter方法是setMessage()。现在让我们使用<attribute>元素在TLD文件中添加此属性,如下所示:

<taglib>
   <tlib-version>1.0</tlib-version>
   <jsp-version>2.0</jsp-version>
   <short-name>Example TLD with Body</short-name>
   
   <tag>
      <name>Hello</name>
      <tag-class>com.tutorialspoint.HelloTag</tag-class>
      <body-content>scriptless</body-content>
      
      <attribute>
         <name>message</name>
      </attribute>
   
   </tag>
</taglib>

让我们按照带有message属性的JSP操作,如下所示:

<%@ taglib prefix = "ex" uri = "WEB-INF/custom.tld"%>

<html>
   <head>
      <title>A sample custom tag</title>
   </head>
   
   <body>
      <ex:Hello message = "This is custom tag" />
   </body>
</html>

这将产生以下结果:

This is custom tag

考虑为属性包含以下属性:

序号 属性&用途
1

name

name元素定义属性的名称。每个属性名称对于特定标签必须唯一。

2

required

这指定此属性是必需的还是可选的。对于可选属性,它将为false。

3

rtexprvalue

声明标签属性的运行时表达式值是否有效

4

type

定义此属性的Java类类型。默认情况下,它被假定为String

5

description

可以提供信息描述。

6

fragment

声明此属性值是否应被视为JspFragment

以下是指定与属性相关的属性的示例:

.....
   <attribute>
      <name>attribute_name</name>
      <required>false</required>
      <type>java.util.Date</type>
      <fragment>false</fragment>
   </attribute>
.....

如果您使用两个属性,则可以如下修改您的TLD:

.....
   <attribute>
      <name>attribute_name1</name>
      <required>false</required>
      <type>java.util.Boolean</type>
      <fragment>false</fragment>
   </attribute>
   
   <attribute>
      <name>attribute_name2</name>
      <required>true</required>
      <type>java.util.Date</type>
   </attribute>
.....

JSP - 表达式语言 (EL)

JSP表达式语言(EL)使您可以轻松访问存储在JavaBeans组件中的应用程序数据。JSP EL允许您创建(a)算术和(b)逻辑表达式。在JSP EL表达式中,您可以使用整数、浮点数、字符串、内置常量true和false表示布尔值,以及null。

简单语法

通常,当您在JSP标签中指定属性值时,只需使用字符串。例如:

<jsp:setProperty name = "box" property = "perimeter" value = "100"/>

JSP EL允许您为这些属性值中的任何一个指定表达式。JSP EL的简单语法如下所示:

${expr}

这里expr指定表达式本身。JSP EL中最常见的运算符是.[]。这两个运算符允许您访问Java Beans和内置JSP对象的各种属性。

例如,上述语法<jsp:setProperty>标签可以用表达式编写,例如:

<jsp:setProperty name = "box" property = "perimeter" 
   value = "${2*box.width+2*box.height}"/>

当JSP编译器在属性中看到${}形式时,它会生成代码来计算表达式并替换表达式的值。

您还可以将JSP EL表达式用于标签的模板文本中。例如,<jsp:text>标签只是将它的内容插入到JSP的主体中。以下<jsp:text>声明将<h1>Hello JSP!</h1>插入到JSP输出中:

<jsp:text>
   <h1>Hello JSP!</h1>
</jsp:text>

您现在可以在<jsp:text>标签(或任何其他标签)的主体中包含JSP EL表达式,使用与您用于属性相同的${}语法。例如:

<jsp:text>
   Box Perimeter is: ${2*box.width + 2*box.height}
</jsp:text>

EL表达式可以使用括号对子表达式进行分组。例如,${(1 + 2) * 3} 等于 9,但 ${1 + (2 * 3)} 等于 7

要停用EL表达式的计算,我们如下指定page指令的isELIgnored属性:

<%@ page isELIgnored = "true|false" %>

此属性的有效值为true和false。如果为true,则在静态文本或标签属性中出现EL表达式时,将忽略它们。如果为false,则容器将计算EL表达式。

EL中的基本运算符

JSP表达式语言(EL)支持Java支持的大多数算术和逻辑运算符。下表列出了最常用的运算符:

序号 运算符&描述
1

.

访问bean属性或Map条目

2

[]

访问数组或List元素

3

( )

对子表达式进行分组以更改计算顺序

4

+

加法

5

-

减法或值的否定

6

*

乘法

7

/ 或 div

除法

8

% 或 mod

取模(余数)

9

== 或 eq

测试相等性

10

!= 或 ne

测试不相等性

11

< 或 lt

测试小于

12

> 或 gt

测试大于

13

<= 或 le

测试小于或等于

14

>= 或 ge

测试大于或等于

15

&& 或 and

测试逻辑AND

16

|| 或 or

测试逻辑OR

17

! 或 not

一元布尔补码

18

empty

测试空变量值

JSP EL中的函数

JSP EL也允许您在表达式中使用函数。这些函数必须在自定义标签库中定义。函数用法具有以下语法:

${ns:func(param1, param2, ...)}

其中ns是函数的命名空间,func是函数的名称,param1是第一个参数值。例如,函数fn:length是JSTL库的一部分。此函数可以按如下方式使用以获取字符串的长度。

${fn:length("Get my length")}

要使用任何标签库(标准或自定义)中的函数,您必须在服务器上安装该库,并且必须使用<taglib>指令将库包含在JSP中,如JSTL章节中所述。

JSP EL隐式对象

JSP表达式语言支持以下隐式对象:

序号 隐式对象&描述
1

pageScope

页面范围内的作用域变量

2

requestScope

请求范围内的作用域变量

3

sessionScope

会话范围内的作用域变量

4

applicationScope

应用程序范围内的作用域变量

5

param

作为字符串的请求参数

6

paramValues

作为字符串集合的请求参数

7

header

作为字符串的HTTP请求头

8

headerValues

作为字符串集合的HTTP请求头

9

initParam

上下文初始化参数

10

cookie

Cookie值

11

pageContext

当前页面的JSP PageContext对象

您可以在表达式中使用这些对象,就像使用变量一样。以下示例将帮助您理解这些概念:

pageContext对象

pageContext对象允许您访问pageContext JSP对象。通过pageContext对象,您可以访问request对象。例如,要访问请求的传入查询字符串,您可以使用以下表达式:

${pageContext.request.queryString}

作用域对象

pageScope、requestScope、sessionScopeapplicationScope变量提供对存储在每个作用域级别的变量的访问。

例如,如果您需要显式访问应用程序作用域中的box变量,则可以通过applicationScope变量访问它,如applicationScope.box

param和paramValues对象

param和paramValues对象允许您访问通常通过request.getParameterrequest.getParameterValues方法可用的参数值。

例如,要访问名为order的参数,请使用表达式${param.order}${param["order"]}

以下是访问名为username的请求参数的示例:

<%@ page import = "java.io.*,java.util.*" %>
<%String title = "Accessing Request Param";%>

<html>
   <head>
      <title><% out.print(title); %></title>
   </head>
   
   <body>
      <center>
         <h1><% out.print(title); %></h1>
      </center>
      
      <div align = "center">
         <p>${param["username"]}</p>
      </div>
   </body>
</html>

param对象返回单个字符串值,而paramValues对象返回字符串数组。

header和headerValues对象

header和headerValues对象允许您访问通常通过request.getHeaderrequest.getHeaders方法可用的标头值。

例如,要访问名为user-agent的标头,请使用表达式${header.user-agent}${header["user-agent"]}

以下是访问名为user-agent的标头参数的示例:

<%@ page import = "java.io.*,java.util.*" %>
<%String title = "User Agent Example";%>

<html>
   <head>
      <title><% out.print(title); %></title>
   </head>
   
   <body>
      <center>
         <h1><% out.print(title); %></h1>
      </center>
      
      <div align = "center">
         <p>${header["user-agent"]}</p>
      </div>
   </body>
</html>

输出将类似于以下内容:

User Agent Example

Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; HPNTDF; .NET4.0C; InfoPath.2)

header对象返回单个字符串值,而headerValues对象返回字符串数组。

JSP - 异常处理

在本章中,我们将讨论如何在JSP中处理异常。在编写JSP代码时,您可能会犯编码错误,这些错误可能发生在代码的任何部分。您的JSP代码中可能会出现以下类型的错误:

已检查异常

已检查异常是指通常是用户错误或程序员无法预见的错误。例如,如果要打开文件但找不到文件,则会发生异常。在编译时,这些异常不能简单地被忽略。

运行时异常

运行时异常是指程序员可能本可以避免的异常。与已检查异常相反,运行时异常在编译时会被忽略。

错误

这些根本不是异常,而是超出用户或程序员控制范围的问题。错误通常在您的代码中被忽略,因为您很少能对错误做些什么。例如,如果发生堆栈溢出,则会发生错误。它们在编译时也会被忽略。

我们将进一步讨论处理JSP代码中发生的运行时异常/错误的方法。

使用Exception对象

异常对象是Throwable的子类的实例(例如,java.lang.NullPointerException),并且仅在错误页面中可用。下表列出了Throwable类中可用的重要方法。

序号 方法和描述
1

public String getMessage()

返回关于发生的异常的详细消息。此消息在Throwable构造函数中初始化。

2

public Throwable getCause()

返回异常的原因,以Throwable对象表示。

3

public String toString()

返回类的名称与getMessage()结果的连接。

4

public void printStackTrace()

toString()的结果以及堆栈跟踪打印到System.err(错误输出流)。

5

public StackTraceElement [] getStackTrace()

返回一个数组,其中包含堆栈跟踪中的每个元素。索引为0的元素表示调用堆栈的顶部,数组中的最后一个元素表示调用堆栈底部的元素。

6

public Throwable fillInStackTrace()

使用当前堆栈跟踪填充此Throwable对象的堆栈跟踪,并添加到堆栈跟踪中的任何先前信息。

JSP允许您为每个JSP指定错误页面。每当页面抛出异常时,JSP容器都会自动调用错误页面。

以下是如何为main.jsp指定错误页面的示例。要设置错误页面,请使用<%@ page errorPage = "xxx" %>指令。

<%@ page errorPage = "ShowError.jsp" %>

<html>
   <head>
      <title>Error Handling Example</title>
   </head>
   
   <body>
      <%
         // Throw an exception to invoke the error page
         int x = 1;
         
         if (x == 1) {
            throw new RuntimeException("Error condition!!!");
         }
      %>
   </body>
</html>

我们现在将编写一个错误处理JSP ShowError.jsp,如下所示。请注意,错误处理页面包含指令<%@ page isErrorPage = "true" %>。此指令导致JSP编译器生成异常实例变量。

<%@ page isErrorPage = "true" %>

<html>
   <head>
      <title>Show Error Page</title>
   </head>
   
   <body>
      <h1>Opps...</h1>
      <p>Sorry, an error occurred.</p>
      <p>Here is the exception stack trace: </p>
      <pre><% exception.printStackTrace(response.getWriter()); %></pre>
   </body>
</html>

访问main.jsp,您将收到类似于以下内容的输出:

java.lang.RuntimeException: Error condition!!!
......

Opps...
Sorry, an error occurred.

Here is the exception stack trace:

使用JSTL标签进行错误页面

您可以使用JSTL标签编写错误页面ShowError.jsp。此页面与上述示例中的逻辑几乎相同,但结构更好,信息更多:

<%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %>
<%@page isErrorPage = "true" %>

<html>
   <head>
      <title>Show Error Page</title>
   </head>
   
   <body>
      <h1>Opps...</h1>
      <table width = "100%" border = "1">
         <tr valign = "top">
            <td width = "40%"><b>Error:</b></td>
            <td>${pageContext.exception}</td>
         </tr>
            
         <tr valign = "top">
            <td><b>URI:</b></td>
            <td>${pageContext.errorData.requestURI}</td>
         </tr>
            
         <tr valign = "top">
            <td><b>Status code:</b></td>
            <td>${pageContext.errorData.statusCode}</td>
         </tr>
            
         <tr valign = "top">
            <td><b>Stack trace:</b></td>
            <td>
               <c:forEach var = "trace" 
                  items = "${pageContext.exception.stackTrace}">
                  <p>${trace}</p>
               </c:forEach>
            </td>
         </tr>
      </table>

   </body>
</html>

访问main.jsp,将生成以下内容:

Opps...

Error:

java.lang.RuntimeException: Error condition!!!

URI:

/main.jsp

Status code:

500

Stack trace:

org.apache.jsp.main_jsp._jspService(main_jsp.java:65)

org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:68)

javax.servlet.http.HttpServlet.service(HttpServlet.java:722)

org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)

javax.servlet.http.HttpServlet.service(HttpServlet.java:722)

使用Try...Catch块

如果要在同一页面中处理错误,并希望采取某些操作而不是触发错误页面,则可以使用try....catch块。

以下是一个简单的示例,演示如何使用try...catch块。让我们将以下代码放入main.jsp中:

<html>
   <head>
      <title>Try...Catch Example</title>
   </head>
   
   <body>
      <%
         try {
            int i = 1;
            i = i / 0;
            out.println("The answer is " + i);
         }
         catch (Exception e) {
            out.println("An exception occurred: " + e.getMessage());
         }
      %>
   </body>
</html>

访问main.jsp,它应该生成类似于以下内容的输出:

An exception occurred: / by zero 

JSP - 调试

在本章中,我们将讨论调试JSP。测试/调试JSP和servlet始终很困难。JSP和Servlet往往涉及大量客户端/服务器交互,这使得错误很可能发生,但难以重现。

以下是一些可能有助于您调试的提示和建议。

使用System.out.println()

System.out.println()易于用作标记,以测试某些代码是否正在执行。我们还可以打印出变量值。请考虑以下其他要点:

  • 由于System对象是核心Java对象的一部分,因此可以在任何地方使用它,而无需安装任何额外的类。这包括Servlet、JSP、RMI、EJB、普通Bean以及独立应用程序

  • 与在断点处停止相比,写入System.out不会过多地干扰应用程序的正常执行流程,这使得在时间至关重要时非常有价值。

以下是使用System.out.println()的语法:

System.out.println("Debugging message");

以下示例演示如何使用System.out.print()

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

<html>
   <head><title>System.out.println</title></head>
   <body>
      <c:forEach var = "counter" begin = "1" end = "10" step = "1" >
      
         <c:out value = "${counter-5}"/></br>
         <% System.out.println( "counter = " + pageContext.findAttribute("counter") ); %>
      </c:forEach>
      
   </body>
</html>

访问上述JSP,浏览器将显示以下结果:

-4
-3
-2
-1
0
1
2
3
4
5

如果您使用的是Tomcat,您还将在日志目录中的stdout.log末尾找到这些行。

counter = 1
counter = 2
counter = 3
counter = 4
counter = 5
counter = 6
counter = 7
counter = 8
counter = 9
counter = 10

通过这种方式,您可以将变量和其他信息引入系统日志,以分析问题的根本原因或出于各种其他原因。

使用JDB记录器

J2SE日志框架旨在为在JVM中运行的任何类提供日志记录服务。我们可以利用此框架记录任何信息。

让我们使用JDK记录器API重写上述示例:

<%@taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %>
<%@page import = "java.util.logging.Logger" %>

<html>
   <head><title>Logger.info</title></head>
   
   <body>
      <% Logger logger = Logger.getLogger(this.getClass().getName());%>

      <c:forEach var = "counter" begin = "1" end = "10" step = "1" >
      <c:set var = "myCount" value = "${counter-5}" />
      <c:out value = "${myCount}"/></br>
         <% String message = "counter = "
            + pageContext.findAttribute("counter") + "myCount = "
            + pageContext.findAttribute("myCount");
            logger.info( message );
         %>
      </c:forEach>
      
   </body>
</html>

上述代码将在浏览器和stdout.log中生成类似的结果,但您将在stdout.log中获得其他信息。我们将使用记录器的info方法,并且仅出于信息目的记录消息。以下是stdout.log文件的快照:

24-Sep-2010 23:31:31 org.apache.jsp.main_jsp _jspService
INFO: counter = 1 myCount = -4
24-Sep-2010 23:31:31 org.apache.jsp.main_jsp _jspService
INFO: counter = 2 myCount = -3
24-Sep-2010 23:31:31 org.apache.jsp.main_jsp _jspService
INFO: counter = 3 myCount = -2
24-Sep-2010 23:31:31 org.apache.jsp.main_jsp _jspService
INFO: counter = 4 myCount = -1
24-Sep-2010 23:31:31 org.apache.jsp.main_jsp _jspService
INFO: counter = 5 myCount = 0
24-Sep-2010 23:31:31 org.apache.jsp.main_jsp _jspService
INFO: counter = 6 myCount = 1
24-Sep-2010 23:31:31 org.apache.jsp.main_jsp _jspService
INFO: counter = 7 myCount = 2
24-Sep-2010 23:31:31 org.apache.jsp.main_jsp _jspService
INFO: counter = 8 myCount = 3
24-Sep-2010 23:31:31 org.apache.jsp.main_jsp _jspService
INFO: counter = 9 myCount = 4
24-Sep-2010 23:31:31 org.apache.jsp.main_jsp _jspService
INFO: counter = 10 myCount = 5

可以使用便捷函数severe()、warning()、info()、config()、fine()、finer()finest()以不同的级别发送消息。这里finest()方法可以用于记录最精细的信息,而severe()方法可以用于记录严重的信息。

您可以使用Log4J框架将消息记录到不同的文件中,具体取决于其严重级别和重要性。

调试工具

NetBeans是一个免费的开源Java集成开发环境,支持开发独立的Java应用程序和Web应用程序,支持JSP和servlet规范,并包括一个JSP调试器。

NetBeans支持以下基本调试功能:

  • 断点
  • 单步执行代码
  • 观察点

您可以参考NetBeans文档以了解上述调试功能。

使用JDB调试器

您可以使用与调试小程序或应用程序相同的jdb命令来调试JSP和servlet。

要调试JSP或servlet,您可以调试sun.servlet.http.HttpServer,然后观察HttpServer如何响应我们从浏览器发出的HTTP请求执行JSP/servlet。这与调试小程序非常相似。不同之处在于,对于小程序,正在调试的实际程序是sun.applet.AppletViewer

大多数调试器通过自动了解如何调试小程序来隐藏此细节。在他们对JSP执行相同的操作之前,您必须通过考虑以下事项来帮助您的调试器:

  • 设置调试器的类路径。这有助于您找到sun.servlet.http.Http-Server和相关类。

  • 设置调试器的类路径。这有助于您找到您的JSP和支持类,通常是ROOT\WEB-INF\classes

设置好正确的类路径后,开始调试sun.servlet.http.HttpServer。您可以在您感兴趣的任何JSP中设置断点,然后使用Web浏览器向HttpServer发出对给定JSP的请求(https://127.0.0.1:8080/JSPToDebug)。这里的执行在断点处停止。

使用注释

代码中的注释可以以多种方式帮助调试过程。注释可以在调试过程中以多种其他方式使用。

JSP使用Java注释,单行(// ...)多行(/* ... */)注释可用于临时删除Java代码的一部分。如果错误消失了,请仔细查看您刚刚注释的代码并找出问题所在。

客户端和服务器标头

有时,当JSP的行为不符合预期时,查看原始HTTP请求和响应很有用。如果您熟悉HTTP的结构,您可以读取请求和响应,并查看这些标头中到底发生了什么。

重要的调试技巧

以下是有关JSP调试的一些更多调试技巧:

  • 要求浏览器显示其正在显示的页面的原始内容。这有助于识别格式问题。通常是“查看”菜单下的一个选项。

  • 通过强制重新加载页面,确保浏览器没有缓存先前请求的输出。使用Netscape Navigator,使用Shift-Reload;使用Internet Explorer使用Shift-Refresh

JSP - 安全性

JavaServer Pages和servlet为Web开发人员提供了多种机制来保护应用程序。通过在应用程序部署描述符中识别资源并为其分配角色,可以声明性地保护资源。

提供了几种身份验证级别,从使用标识符和密码的基本身份验证到使用证书的复杂身份验证。

基于角色的身份验证

servlet规范中的身份验证机制使用一种称为基于角色的安全的技术。其思想是,您创建角色并按角色限制资源,而不是在用户级别限制资源。

您可以在文件tomcat-users.xml中定义不同的角色,该文件位于Tomcat主目录下的conf中。此文件的示例如下所示:

<?xml version = '1.0' encoding = 'utf-8'?>
<tomcat-users>
   <role rolename = "tomcat"/>
   <role rolename = "role1"/>
   <role rolename = "manager"/>
   <role rolename = "admin"/>
   <user username = "tomcat" password = "tomcat" roles = "tomcat"/>
   <user username = "role1" password = "tomcat" roles = "role1"/>
   <user username = "both" password = "tomcat" roles = "tomcat,role1"/>
   <user username = "admin" password = "secret" roles = "admin,manager"/>
</tomcat-users>

此文件定义了用户名、密码角色之间简单的映射。请注意,给定用户可能具有多个角色;例如,username = "both"位于“tomcat”角色和“role1”角色中。

识别和定义不同的角色后,可以通过使用web.xml文件中(位于WEB-INF目录下)的<security-constraint>元素,对不同的Web应用程序资源进行基于角色的安全限制。

以下是web.xml中的一个示例条目:

<web-app>
   ...
   <security-constraint>
      <web-resource-collection>
         <web-resource-name>SecuredBookSite</web-resource-name>
         <url-pattern>/secured/*</url-pattern>
         <http-method>GET</http-method>
         <http-method>POST</http-method>
      </web-resource-collection>
      
      <auth-constraint>
         <description>
            Let only managers use this app
         </description>
         <role-name>manager</role-name>
      </auth-constraint>
   </security-constraint>
   
   <security-role>
      <role-name>manager</role-name>
   </security-role>
   
   <login-config>
      <auth-method>BASIC</auth-method>
   </login-config>
   ...
</web-app>

上述条目将表示:

  • 任何对与/secured/*匹配的URL的HTTP GET或POST请求都将受安全限制。

  • 具有管理者角色的人员可以访问受保护的资源。

  • login-config元素用于描述BASIC形式的身份验证。

如果您尝试浏览包含/security目录的任何URL,将显示以下对话框,要求输入用户名和密码。如果您提供用户“admin”和密码“secret”,那么您将可以访问与/secured/*匹配的URL,因为我们已将用户admin定义为具有管理者角色的用户,该用户被允许访问此资源。

基于表单的身份验证

当您使用FORM身份验证方法时,必须提供一个登录表单以提示用户输入用户名和密码。以下是login.jsp的简单代码。这有助于为相同目的创建表单:

<html>
   <body bgcolor = "#ffffff">
      
      <form method = "POST" action ="j_security_check">
         <table border = "0">
            <tr>
               <td>Login</td>
               <td><input type = "text" name="j_username"></td>
            </tr>
            <tr>
               <td>Password</td>
               <td><input type = "password" name="j_password"></td>
            </tr>
         </table>
         <input type = "submit" value = "Login!">
      </form>
      
   </body>
</html>

这里您必须确保登录表单必须包含名为j_usernamej_password的表单元素。<form>标签中的操作必须为j_security_check。必须使用POST作为表单方法。同时,您将需要修改<login-config>标签以将auth-method指定为FORM:

<web-app>
   ...
   <security-constraint>
      <web-resource-collection>
         <web-resource-name>SecuredBookSite</web-resource-name>
         <url-pattern>/secured/*</url-pattern>
            <http-method>GET</http-method>
            <http-method>POST</http-method>
      </web-resource-collection>
      
      <auth-constraint>
         <description>Let only managers use this app</description>
         <role-name>manager</role-name>
      </auth-constraint>
   </security-constraint>
   
   <security-role>
      <role-name>manager</role-name>
   </security-role>
   
   <login-config>
      <auth-method>FORM</auth-method>
      <form-login-config>
         <form-login-page>/login.jsp</form-login-page>
         <form-error-page>/error.jsp</form-error-page>
      </form-login-config>
   </login-config>
   ...
</web-app>

现在,当您尝试访问任何具有URL /secured/*的资源时,它将显示上述表单,要求您输入用户 ID 和密码。当容器看到“j_security_check”操作时,它会使用一些内部机制来验证调用方。

如果登录成功并且调用方被授权访问受保护的资源,则容器从那时起使用会话 ID 来识别调用方的登录会话。容器使用包含会话 ID 的 cookie 来维护登录会话。服务器将 cookie 发送回客户端,只要调用方在后续请求中提供此 cookie,容器就会知道调用方是谁。

如果登录失败,则服务器会发送回由 form-error-page 设置标识的页面。

这里,j_security_check 是使用基于表单登录的应用程序必须为登录表单指定的动作。在同一表单中,您还应该有一个名为j_username 的文本输入控件和一个名为j_password密码输入控件。当您看到此信息时,这意味着表单中包含的信息将提交到服务器,服务器将检查名称和密码。如何做到这一点是特定于服务器的。

查看标准 Realm 实现以了解j_security_check 如何在 Tomcat 容器中工作。

Servlet/JSP 中的编程安全

HttpServletRequest 对象提供以下方法,这些方法可用于在运行时挖掘安全信息:

序号 方法及描述
1

String getAuthType()

getAuthType() 方法返回一个 String 对象,该对象表示用于保护 Servlet 的身份验证方案的名称。

2

boolean isUserInRole(java.lang.String role)

isUserInRole() 方法返回一个布尔值:如果用户在给定角色中,则为 true;如果用户不在给定角色中,则为 false。

3

String getProtocol()

getProtocol() 方法返回一个 String 对象,表示用于发送请求的协议。可以检查此值以确定是否使用了安全协议。

4

boolean isSecure()

isSecure() 方法返回一个布尔值,表示请求是否使用 HTTPS 发出。值为 true 表示使用了 HTTPS 并且连接是安全的。值为 false 表示请求未使用 HTTPS。

5

Principle getUserPrinciple()

getUserPrinciple() 方法返回一个 java.security.Principle 对象,其中包含当前已认证用户的名称。

例如,对于链接到管理人员页面的 JavaServer 页面,您可能具有以下代码:

<% if (request.isUserInRole("manager")) { %>
   <a href = "managers/mgrreport.jsp">Manager Report</a>
   <a href = "managers/personnel.jsp">Personnel Records</a>
<% } %>

通过检查 JSP 或 servlet 中用户的角色,您可以自定义网页以仅向用户显示她可以访问的项目。如果您需要用户在身份验证表单中输入的用户名,则可以在请求对象中调用getRemoteUser 方法。

JSP - 国际化 | i18n | l10n

在本章中,我们将讨论 JSP 中国际化的概念。在继续之前,让我们了解以下三个重要术语:

  • 国际化 (i18n) - 这意味着使网站能够提供内容的不同版本,这些版本已翻译成访问者的语言或国籍。

  • 本地化 (l10n) - 这意味着向网站添加资源以使其适应特定的地理或文化区域,例如将网站翻译成印地语。

  • 区域设置 (locale) - 这是一个特定的文化或地理区域。它通常被称为语言符号后跟国家/地区符号,这两个符号用下划线分隔。例如,“en_US”表示美国英语区域设置。

在构建全球网站时,需要处理许多事项。本教程不会详细介绍所有内容,但它将为您提供一个很好的示例,说明您如何通过区分其位置(即区域设置)来为互联网社区提供不同语言的网页。

JSP 可以根据请求者的区域设置选择合适的站点版本,并根据本地语言、文化和要求提供相应的站点版本。以下是请求对象的方法,该方法返回 Locale 对象。

java.util.Locale request.getLocale() 

检测区域设置

以下是您可以用来检测请求者的位置、语言以及当然还有区域设置的重要区域设置方法。以下所有方法都显示在请求者的浏览器中设置的国家/地区名称和语言名称。

序号 方法及描述
1

String getCountry()

此方法以 ISO 3166 2 个字母格式返回此区域设置的大写国家/地区代码。

2

String getDisplayCountry()

此方法返回适合显示给用户的区域设置国家/地区的名称。

3

String getLanguage()

此方法以 ISO 639 格式返回此区域设置的小写语言代码。

4

String getDisplayLanguage()

此方法返回适合显示给用户的区域设置语言的名称。

5

String getISO3Country()

此方法返回此区域设置国家/地区的三个字母缩写。

6

String getISO3Language()

此方法返回此区域设置语言的三个字母缩写。

示例

以下示例显示如何在 JSP 中显示请求的语言和关联的国家/地区:

<%@ page import = "java.io.*,java.util.Locale" %>
<%@ page import = "javax.servlet.*,javax.servlet.http.* "%>
<%
   //Get the client's Locale
   Locale locale = request.getLocale();
   String language = locale.getLanguage();
   String country = locale.getCountry();
%>

<html>
   <head>
      <title>Detecting Locale</title>
   </head>

   <body>
      <center>
         <h1>Detecting Locale</h1>
      </center>
      
      <p align = "center">
         <% 
            out.println("Language : " + language  + "<br />");
            out.println("Country  : " + country   + "<br />");
         %>
      </p>
   </body>
</html>

语言设置

JSP 可以输出用西欧语言(如英语、西班牙语、德语、法语、意大利语、荷兰语等)编写的页面。这里重要的是设置 Content-Language 标头以正确显示所有字符。

另一个重点是使用 HTML 实体显示所有特殊字符;例如,"&#241;" 表示"ñ""&#161;" 表示"¡",如下所示:

<%@ page import = "java.io.*,java.util.Locale" %>
<%@ page import = "javax.servlet.*,javax.servlet.http.* "%>

<%
   // Set response content type
   response.setContentType("text/html");
   
   // Set spanish language code.
   response.setHeader("Content-Language", "es");
   String title = "En Español";
%>

<html>
   <head>
      <title><%  out.print(title); %></title>
   </head>
   
   <body>
      <center>
         <h1><%  out.print(title); %></h1>
      </center>
      
      <div align = "center">
         <p>En Español</p>
         <p>¡Hola Mundo!</p>
      </div>
   </body>
</html>

特定于区域设置的日期

您可以使用java.text.DateFormat 类及其静态getDateTimeInstance( ) 方法来格式化特定于区域设置的日期和时间。以下是显示如何格式化特定于给定区域设置的日期的示例:

<%@ page import = "java.io.*,java.util.Locale" %>
<%@ page import = "javax.servlet.*,javax.servlet.http.* "%>
<%@ page import = "java.text.DateFormat,java.util.Date" %>

<%
   String title = "Locale Specific Dates";
   
   //Get the client's Locale
   Locale locale = request.getLocale( );
   
   String date = DateFormat.getDateTimeInstance(
      DateFormat.FULL, 
      DateFormat.SHORT, 
      locale).format(new Date( ));
%>

<html>
   
   <head>
      <title><% out.print(title); %></title>
   </head>
   
   <body>
      <center>
         <h1><% out.print(title); %></h1>
      </center>
      
      <div align = "center">
         <p>Local Date: <%  out.print(date); %></p>
      </div>
   </body>
</html>

特定于区域设置的货币

您可以使用java.txt.NumberFormat 类及其静态getCurrencyInstance( ) 方法以特定于区域设置的货币格式化数字(例如 long 或 double 类型)。以下是显示如何格式化特定于给定区域设置的货币的示例:

<%@ page import = "java.io.*,java.util.Locale" %>
<%@ page import = "javax.servlet.*,javax.servlet.http.* "%>
<%@ page import = "java.text.NumberFormat,java.util.Date" %>

<%
   String title = "Locale Specific Currency";
   
   //Get the client's Locale
   Locale locale = request.getLocale( );
   
   NumberFormat nft = NumberFormat.getCurrencyInstance(locale);
   String formattedCurr = nft.format(1000000);
%>

<html>
   
   <head>
      <title><% out.print(title); %></title>
   </head>
   
   <body>
      <center>
         <h1><% out.print(title); %></h1>
      </center>
      
      <div align = "center">
         <p>Formatted Currency: <%  out.print(formattedCurr); %></p>
      </div>
   </body>
</html>

特定于区域设置的百分比

您可以使用java.txt.NumberFormat 类及其静态getPercentInstance( ) 方法获取特定于区域设置的百分比。以下示例显示如何格式化特定于给定区域设置的百分比:

<%@ page import = "java.io.*,java.util.Locale" %>
<%@ page import = "javax.servlet.*,javax.servlet.http.* "%>
<%@ page import = "java.text.NumberFormat,java.util.Date" %>

<%
   String title = "Locale Specific Percentage";
   
   //Get the client's Locale
   Locale locale = request.getLocale( );
   
   NumberFormat nft = NumberFormat.getPercentInstance(locale);
   String formattedPerc = nft.format(0.51);
%>

<html>
   
   <head>
      <title><% out.print(title); %></title>
   </head>
   
   <body>
      <center>
         <h1><% out.print(title); %></h1>
      </center>
      
      <div align = "center">
         <p>Formatted Percentage: <%  out.print(formattedPerc); %></p>
      </div>
   </body>
</html>
广告