JavaServer Pages 全面解析
1. JSP 基础与嵌入 Java 代码
在创建网页时,你可能认为创建一个简单的
HelloWorld.html
页面就足够了,无需额外的代码生成。但这仅适用于静态页面,即不使用任何外部动态数据的页面。因为 HTML 是一种标记语言,并非编程语言,它甚至无法进行简单的加法运算,而 JSP 则可以做到。
JSP 定义了一些标签,允许将 Java 代码嵌入到 HTML 页面中。当在后台自动生成 Servlet 时,这些 Java 代码也会被包含在内并作为 Servlet 的一部分执行。JSP 标签用尖括号括起来,例如
<%=...%>
标签用于显示变量或表达式的值,如
<%=2 + 2%>
。在 JSP 引擎执行 Servlet 生成过程中,这些标签会被替换为常规的 Java 代码,例如
<%=2 + 2%>
会被 JSP 容器自动替换为
out.println(2 + 2);
。
以下是一个名为
MyCalculator.jsp
的简单示例:
<html>
<body>
HTML created by Matilda goes here...
<br>
You may not know that 2 + 2 is <%= 2 + 2%>
<br>
More HTML created by Matilda goes here...
</body>
</html>
要创建一个 JSP 项目,可以在 Eclipse 中创建一个名为
Lesson 28
的动态 Web 项目。它会自动在
WebContent
目录下创建一个名为
index.jsp
的文件,这是一个
Hello World
JSP。部署任何 JSP 只需将 JSP 文件复制到 JSP 容器的文档根目录即可。如果 JSP 是多文件项目的一部分,很可能会将它们打包成 WAR 文件进行部署。
具体操作步骤如下:
1. 在 Eclipse 中创建动态 Web 项目
Lesson 28
。
2. 右键单击
index.jsp
并选择
Run on Server
,即可看到
Hello World
网页。
3. 复制
index.jsp
并重命名为
MyCalculator.jsp
,将
<body>
部分的内容替换为上述
MyCalculator.jsp
的
<body>
部分内容。
4. 运行
MyCalculator.jsp
,你会在 Eclipse 中看到网页,表达式
<%2 + 2%>
会被预编译并替换为 4。
JSP 实际上就是一个从包含有效 HTML 和 JSP 标签的文件自动生成的 Servlet。
2. 隐式 JSP 对象
由于 JSP 是基于 Servlet 构建的,因此主要概念保持不变。以下是一些可以在 JSP 页面中使用的预定义变量,这些变量由 JSP 容器初始化,无需显式声明即可使用:
| 变量名 | 说明 |
| ---- | ---- |
|
request
| 与
HttpServletRequest
用途相同 |
|
response
| 与
HttpServletResponse
用途相同 |
|
out
| 表示输出写入流
JspWriter
,与 Servlet 中的
HttpServletResponse.getWriter()
指向同一对象。例如,一个返回
CurrencyConverter
类结果的最简单 JSP 可能如下:
<html>
<body>
<% out.println(CurrencyConverter.getDollarRate()); %>
</body>
</html>
``` |
| `session` | 表示用户的 `HTTPSession` 对象实例 |
| `exception` | 表示 `Throwable` 对象实例,包含错误信息,仅在 JSP 错误页面中可用 |
| `page` | 表示 JSP 的 Servlet 实例 |
| `pageContext` | 表示 JSP 上下文,用于标签库 |
| `application` | 提供对 Web 上下文的访问,用途类似于 `ServletContext` |
| `config` | 提供 JSP 容器使用的初始化信息,用途类似于 `ServletConfig` 类 |
#### 3. JSP 标签概述
每个 JSP 标签以尖括号开始和结束,可以包含在任何 HTML 文件中,但需要将其保存为 `.jsp` 文件,以便 JSP 容器正确识别和处理。以下是 JSP 标签的简要概述:
- **指令(Directives)**:指令不会生成屏幕输出,但会指示 JSP 容器应用于 JSP 的规则。一些 JSP 指令包括 `page`、`include`、`attribute` 和 `taglib`。
- `page` 指令以 `<%@ page` 开头,仅在当前页面有效,可用于导入包、设置会话、指定错误页面等,例如 `<%@ page import=”java.io.*” %>`。
- `include` 指令允许在页面编译为 Servlet 时包含文件中的任何文本或另一个 JSP 中的代码,例如 `<%@ jsp:include page=”calcBankRates.jsp” %>` 和 `<%@ include file=”bankRates.txt” %>`。
- `taglib` 指令用于指定第三方自定义标签库的位置,例如 `<%@ taglib uri=”my_taglib.tld” prefix=”test” %>`。
- `attribute` 指令用于定义自定义标签的属性,例如 `<%@ attribute name=”corporate_logo_file_name” %>`。
- **声明(Declarations)**:用于在使用变量之前进行声明,例如 `<%! double salary; %>`,该变量仅在当前页面可见。也可以用同样的方式声明 Java 方法,例如:
```jsp
<%! private void myMethod(){
...
}%>
声明块中的代码会转换为生成的 Servlet 中的 Java 代码。
-
表达式(Expressions)
:以
<%=
开头,可以包含任何 Java 表达式,表达式的值会被计算并显示在 HTML 页面中,替换标签本身,例如
<%= salary*1.2 %>
。
-
脚本片段(Scriptlets)
:最初用于让 JSP 开发人员将任何有效的 Java 代码放入生成的 Servlet 的
_jspService()
方法中,该方法相当于 Servlet 的
service()
方法。例如
<% lastName = “Smith”; %>
。不过,随着 JSP 标准标签库(JSTL)和表达式语言(EL)的出现,现在不再需要使用脚本片段,但这种语法仍然有效。
-
注释(Comments)
:以
<%--
开头并以
--%>
结尾的注释在 JSP 源代码中可见,但不会包含在生成的 HTML 页面中,例如
<%-- Some comments --%>
。如果希望注释保留在生成的网页中,可以使用常规的 HTML 注释符号
<!-- Some comments -->
。
-
标准动作(Standard Actions)
:
-
jsp:include
元素在运行时包含页面内容,而
include
指令在编译时包含内容,例如
<jsp:include page “header.jsp” />
。
-
forward
元素用于将程序流程从当前 JSP 重定向到另一个 JSP,同时保留请求和响应对象,例如
<jsp:forward page = “someOther.jsp” />
。另一种重定向方式是使用
response.sendRedirect(someURL)
,但这种方式会创建新的请求和响应对象,导致客户端向服务器发出请求。
-
plugin
元素确保 JSP 包含一个 applet 或 Java bean。在运行时,Web 浏览器会将此标签替换为
<object>
或
<embed>
标签,例如:
<jsp:plugin type=applet code=”PriceQuotes.class” >
<jsp:params>
<jsp:param name=”userID” value=”SCOTT” />
<jsp:param name=”password” value=”TIGER” />
</jsp:params>
</jsp:plugin>
4. 错误页面
假设我们有一个名为
calcTax.jsp
的文件,其中的代码可能会抛出 Java 异常。为了避免用堆栈跟踪输出屏幕吓到用户,可以准备一个友好的
taxErrors.jsp
文件,用通俗易懂的语言解释问题。
calcTax.jsp
可能包含一个 HTML
<form>
,用户在其中输入总收入和受抚养人数。税收计算请求会发送到服务器的
CalcTax
Java 类,该类在处理过程中可能会抛出异常。需要在
calcTax.jsp
中包含在出现异常时要显示的错误页面的名称:
<html>
Some code to calculate tax and other HTML stuff goes here
...
<%@ page errorPage=taxErrors.jsp %>
</html>
以下是
taxErrors.jsp
的示例:
<html>
<body>
Unfortunately there was a problem during your tax calculations. We are
working on this issue - please try again in 10 minutes.
If the problem persists, please contact our award winning technical support
team at (212) 555-2222 and provide them with the following information:
<br>
<%=exception.toString()>
</body>
</html>
5. JavaBeans
JavaBeans 规范将 Bean 定义为实现
Serializable
接口的 Java 类,它具有一个公共的无参数构造函数、私有字段和公共的 setter 和 getter 方法。Java Bean 主要用于数据存储和交换,在 JSP 中使用 Java Bean 可以避免将 Java 代码与 HTML 混合。
在基于 JSP 的 Web 应用程序的 MVC 模式中,JSP 属于视图层,Servlet 可以充当控制器,Java Bean 可以代表模型。虽然可以将 HTML 与脚本片段、声明和表达式中编写的业务逻辑混合在一起,但应该避免这样做,而是将表示层与业务逻辑处理和数据存储分离。这样做有两个好处:一是可以更轻松地在设计师和开发人员之间分配工作;二是可以使用相同的 Java 代码实现多种表示解决方案,例如为移动设备提供不同的 UI。
以下是一个名为
Student
的 Java Bean 示例:
import java.io.Serializable;
class Student implements Serializable{
private String lastName;
private String firstName;
private boolean undergraduate;
Student(){
// constructor’s code goes here
}
public String getLastName(){
return lastName;
}
public String getFirstName(){
return firstName;
}
public void setLastName(String value){
lastName = value;
}
public void setFirstName (String value){
firstName = value;
}
public void setUndergraduate(boolean value){
undergraduate = value;
}
public boolean isUndergraduate (){
return undergraduate;
}
}
需要注意的是,不要将 JavaBeans 与 Enterprise Java Beans(EJB)混淆,它们是不同的概念。
6. 在 JSP 中使用 JavaBeans
要在 JSP 中使用 Java Bean,首先需要指定其名称和位置,然后就可以设置或获取其属性。以下是一些使用 Bean 的示例:
<jsp:useBean id=”Student” class=”com.harward.Student” />
<jsp:getProperty name=”Student” property=”LastName” />
<jsp:setProperty name=”Student” property=”LastName” value=”Smith”/>
如果 HTML 表单中的属性名称与 Bean 中的属性名称相同,可以使用星号表示法更简单地映射 HTML 表单和 Bean 的字段:
<jsp:setProperty name=”Student” property=”*” />
Java Bean 的作用域可以通过
jsp:useBean
标签的
scope
属性来定义,主要有以下几种作用域:
| 作用域 | 说明 | 示例 |
| ---- | ---- | ---- |
|
page
| Bean 仅在当前页面可用,用户离开页面后即被销毁,这是默认作用域 |
<jsp:useBean id=”Student” class=”com.harward.Student” scope=”page” />
|
|
request
| Bean 在请求对象的生命周期内可用,即使通过
jsp:forward
标签将控制重定向到不同的 JSP,由于使用的是相同的请求对象,Bean 在新页面上仍然可用 |
<jsp:useBean id=”Student” class=”com.harward.Student” scope=”request” />
|
|
session
| Bean 在用户会话结束之前对所有页面都可用 |
<jsp:useBean id=”Student” class=”com.harward.Student” scope=”session” />
|
|
application
| Bean 对所有用户和所有页面都可用,是全局 Bean |
<jsp:useBean id=”Student” class=”com.harward.Student” scope=”application” />
|
7. 从 Servlet 加载 JSP
为了实现表示层与处理层的分离,JSP 应尽量减少处理逻辑。当 Servlet 接收到要发送给用户的数据时,应加载并发送 JSP 页面给客户端,而不是直接发送硬编码的 HTML 标签。理想情况下,JSP 应由 Web 设计师进行布局。
假设一个 Servlet 需要根据用户在 HTML 窗口中的选择加载不同的 JSP。如果不需要获取新的请求和响应对象副本,则需要创建一个
RequestDispatcher
类的实例,并调用其
forward()
方法,同时提供
HttpServletRequest
和
HttpServletResponse
作为参数。以下是一个示例:
public class MyServlet extends HttpServlet{
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException {
ServletContext context = getServletContext();
RequestDispatcher requestDisp = null;
String make = req.getParameter(“carMake”);
if (make.equals(“Toyota”) {
requestDisp = context.getRequestDispatcher(“Toyota.jsp”);
requestDisp.forward(req,res);
}
else if (make.equals(“Nissan”) {
requestDisp = context.getRequestDispatcher(“Nissan.jsp”);
requestDisp.forward(req,res);
}
}
}
在某些情况下,当前 Servlet 会处理与用户的所有交互,只需要加载另一个 Servlet 或 JSP 的代码,此时可以使用
include()
方法代替
forward()
方法:
requestDisp.include(req,res);
由于这种重定向是在服务器端进行的,因此 Web 浏览器的地址栏中仍然显示初始 URL。如果需要提供新的 URL(例如允许用户对结果页面进行书签操作),可以使用
response.sendRedirect(“/new_URL”)
。
8. 标签库
使用包含自定义和可重用标签的标签库是减少 JSP 代码量的另一种方法。这些标签库可以是自己创建的,也可以是他人创建的。每个自定义标签看起来与常规标签类似,但实际上由程序员编写的 Java 类提供支持,以实现所需的功能。
如果要创建自己的自定义标签用于 JSP,需要完成以下步骤:
1. 创建一个标签库描述符,这是一个扩展名为
.tld
的 XML 文件,必须部署在
WEB-INF/tags
目录下。
2. 创建提供标签业务逻辑支持的 Java 类,这些类通常以 JAR 文件的形式部署在
WEB-INF/lib
目录下。
3. 将标签库注册到 Web 应用程序中。
以下是一个示例标签库描述符文件:
<?xml version=” 1. 0” encoding=”UTF-8” ?>
<taglib xmlns=” http: / / j ava. sun. com/xml/ns/ j 2ee”
xmlns: xsi=” http: //www. w3. org/ 2 001/XMLSchema-instance”
xsi: schemaLocation=” http: //java. sun. com/ xml/ns/j2 ee
http: //java. sun. com/ xml/ns/j2 ee/web-jsptaglibrary_2 _0. xsd”
version=”2 . 0” >
<tlib-version>1.0</ tlib-version>
<shortname>sts</shortname>
<uri>http://www.mystockserver.com:8080/taglib</uri>
<info>Wall Street tag library</info>
<tag>
<name>DowJones</name>
<tagclass>DowJonesTag</tagclass>
<bodycontent>empty</bodycontent>
<info>Displays the Dow Jones index</info>
</tag>
</taglib>
支持 JSP 标签的类(例如
DowJonesHandler
)必须实现
javax.servlet.jsp.tagext.SimpleTag
接口或继承
SimpleTagSupport
。JSP 容器会调用
DowJonesHandler
的方法来设置 JSP 上下文、开始执行标签代码等。需要将标签的逻辑放在
doTag()
方法中,该方法在请求时由容器调用。
以下是
DowJonesHandler
类的示例:
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import java.io.*;
public class DowJonesHandler extends SimpleTagSupport{
public int doTag() throws JspException, IOException{
String dowQuote;
// Obtain the DowJones quote by accessing
// http://finance.yahoo.com/q?d=t&s=^DJI or similar
dowQuote=...;
// and write it to the client
JspWriter out = getJspContext().getOut();
out.print(“The last price is ” + dowQuote);
}
}
要使标签库能被 JSP 容器识别,需要在
web.xml
文件中插入以下片段进行注册:
<taglib>
<taglib-uri>
http://www.mystockserver.com/taglib
</taglib-uri>
<taglib-location>
/WEB-INF/taglib.tld
</taglib-location>
</taglib>
完成上述操作后,可以创建一个简单的
test.jsp
文件并开始使用标签库。以下是一个使用自定义标签的示例:
<html>
<head>
<%@ taglib uri=http://www.mystockserver.com/taglib prefix=”sts” %>
</head>
<body>
Today’s Dow Jones index: <sts:DowJones/>
</body>
</html>
通过以上介绍,我们全面了解了 JSP 的相关知识,包括基础概念、标签使用、JavaBeans 的应用以及从 Servlet 加载 JSP 和标签库的使用等内容。这些知识可以帮助我们更好地开发基于 JSP 的 Web 应用程序。
JavaServer Pages 全面解析
9. JSP 项目开发流程总结
为了让大家更清晰地了解 JSP 项目的开发流程,我们可以通过一个 mermaid 流程图来展示:
graph LR
A[项目创建] --> B[创建 JSP 页面]
B --> C[嵌入 Java 代码]
C --> D[使用隐式对象和标签]
D --> E[处理错误页面]
E --> F[使用 JavaBeans]
F --> G[从 Servlet 加载 JSP]
G --> H[使用标签库]
H --> I[部署和测试]
具体的开发步骤如下:
1.
项目创建
:在 Eclipse 等开发工具中创建动态 Web 项目,如创建名为
Lesson 28
的项目,会自动生成
index.jsp
文件。
2.
创建 JSP 页面
:可以复制
index.jsp
并重命名为其他 JSP 文件,如
MyCalculator.jsp
,并编写 HTML 和 JSP 代码。
3.
嵌入 Java 代码
:使用 JSP 标签将 Java 代码嵌入到 HTML 页面中,如
<%= 2 + 2%>
会被替换为相应的 Java 代码执行。
4.
使用隐式对象和标签
:利用预定义的隐式对象,如
request
、
response
等,以及各种 JSP 标签,如指令、声明、表达式等完成页面功能。
5.
处理错误页面
:为可能抛出异常的 JSP 文件准备友好的错误页面,如
calcTax.jsp
对应
taxErrors.jsp
。
6.
使用 JavaBeans
:定义符合 JavaBeans 规范的类,用于数据存储和交换,在 JSP 中使用
jsp:useBean
等标签操作 Bean。
7.
从 Servlet 加载 JSP
:在 Servlet 中根据用户请求加载相应的 JSP 页面,使用
RequestDispatcher
的
forward()
或
include()
方法。
8.
使用标签库
:创建或使用现有的标签库,减少 JSP 代码量,提高代码的可维护性。
9.
部署和测试
:将项目部署到 JSP 容器中,进行测试,确保页面功能正常。
10. JSP 与 MVC 模式的结合优势
在基于 JSP 的 Web 应用程序中,结合 MVC(Model-View-Controller)模式具有显著优势。以下是一个表格展示 JSP、Servlet 和 JavaBeans 在 MVC 模式中的角色:
| MVC 角色 | 对应组件 | 说明 |
| ---- | ---- | ---- |
| 视图(View) | JSP | 负责页面的显示,提供用户界面,将数据呈现给用户。 |
| 控制器(Controller) | Servlet | 处理用户请求,调用相应的业务逻辑,控制程序的流程。 |
| 模型(Model) | JavaBeans | 负责数据的存储和业务逻辑的处理,与数据库交互等。 |
通过这种结合,可以实现表示层与业务逻辑层、数据存储层的分离,带来以下好处:
-
分工明确
:设计师可以专注于 JSP 页面的设计,开发人员可以专注于 Servlet 和 JavaBeans 的编写,提高开发效率。
-
可维护性高
:当业务逻辑发生变化时,只需修改 JavaBeans 或 Servlet,而不会影响 JSP 页面的显示;当页面布局需要调整时,只需修改 JSP 页面,不会影响业务逻辑。
-
可扩展性强
:可以方便地添加新的功能模块,如添加新的 JavaBeans 来处理新的业务逻辑,添加新的 JSP 页面来提供新的用户界面。
11. JSP 开发中的注意事项
在使用 JSP 进行开发时,有一些注意事项需要我们关注:
-
避免代码混合
:尽量避免将大量的 Java 代码直接写在 JSP 页面中,应使用 JavaBeans 和 Servlet 来处理业务逻辑,保持 JSP 页面的简洁,只负责数据的显示。
-
作用域的正确使用
:在使用 JavaBeans 时,要根据实际需求选择合适的作用域,如
page
、
request
、
session
或
application
,避免数据的错误共享或丢失。
-
错误处理
:要为可能出现异常的 JSP 页面准备友好的错误页面,避免给用户显示复杂的错误信息,提高用户体验。
-
标签库的使用
:合理使用标签库可以减少代码量,但要注意标签库的注册和使用规范,确保标签能正常工作。
12. JSP 与其他技术的对比
与其他 Web 开发技术相比,JSP 具有自己的特点。以下是 JSP 与 PHP、ASP.NET 的简单对比:
| 技术 | 优点 | 缺点 |
| ---- | ---- | ---- |
| JSP | 基于 Java 平台,具有跨平台性,可与 Java 生态系统中的各种技术集成,适合开发大型企业级应用。 | 开发环境相对复杂,学习成本较高。 |
| PHP | 语法简单,易于学习,开发效率高,适合快速开发小型网站。 | 缺乏企业级应用开发的支持,性能相对较低。 |
| ASP.NET | 与 Windows 平台集成度高,开发工具强大,适合开发基于 Windows 平台的 Web 应用。 | 跨平台性较差,依赖于 Microsoft 的技术栈。 |
13. 未来 JSP 的发展趋势
随着 Web 开发技术的不断发展,JSP 也在不断演进。虽然现在有很多新的前端框架和后端技术出现,但 JSP 仍然在一些企业级应用中广泛使用。未来,JSP 可能会朝着以下方向发展:
-
与新技术的融合
:JSP 可能会与前端的 Vue.js、React 等框架结合,提供更好的用户体验;与后端的微服务架构结合,提高系统的可扩展性和性能。
-
性能优化
:通过优化 JSP 引擎和 Servlet 容器,提高 JSP 页面的响应速度和处理能力。
-
简化开发流程
:不断改进开发工具和框架,降低 JSP 开发的难度和复杂度,提高开发效率。
通过对 JSP 的全面学习和了解,我们可以更好地利用 JSP 技术开发出高质量的 Web 应用程序。同时,我们也要关注技术的发展趋势,不断学习和掌握新的知识,以适应不断变化的市场需求。
超级会员免费看
1217

被折叠的 条评论
为什么被折叠?



