Java编程:Servlet与事务处理
1. Java事务中的Savepoint
在Java编程里,事务不应仅因为在事务执行时无法发送短信或电子邮件警报就回滚。这时可使用Savepoint将事务回滚到事务中的某个设定点。Savepoint是
java.sql
包中的一个接口,在JDBC 3.0 API中引入。所有到保存点之前所做的更改都会被提交,而保存点之后的更改则会被回滚。以下代码展示了如何回滚到保存点
sp1
,即回滚
sp1
之后的所有更改,并提交
sp1
之前的所有更改:
try {
con.setAutoCommit(false); //
Statement stmt1 = con.createStatement();
Statement stmt2 = con.createStatement();
stmt1.executeUpdate("Query 1");
Savepoint sp1 = con.setSavepoint("SavePoint1");
stmt1.executeUpdate("Query 2");
con.commit();
/* commit the changes to the database and make them
permanent. */
...
} catch(SQLException se) {
try{
con.rollback(sp1); // roll back the changes up to the savepoint
}catch(SQLException){}
}
2. Servlet概述
Servlet是Java服务器端程序,用于接收客户端请求(通常是HTTP请求),处理这些请求并生成响应(通常是HTTP响应)。请求源自客户端的Web浏览器,并被路由到位于合适Web服务器内的Servlet。Servlet在Servlet容器中执行,该容器位于像Apache Tomcat这样的Web服务器中。较新的Tomcat版本还包含JSP(Java服务器页面)容器。通常,Web客户端和Servlet之间使用HTTP(超文本传输协议),但也可以使用其他协议,如FTP(文件传输协议)。
2.1 Servlet的生命周期
Servlet有其自身的执行生命周期,包括以下三个方法,具体流程如下:
graph LR
A[接收客户端请求] --> B[定位并加载Servlet]
B --> C[实例化Servlet]
C --> D[调用init()方法初始化]
D --> E[调用service()方法处理请求并生成响应]
E --> F{请求类型}
F -- get请求 --> G[调用doGet()方法]
F -- post请求 --> H[调用doPost()方法]
G --> I[处理完成]
H --> I[处理完成]
I --> J[调用destroy()方法进行清理]
-
init()方法:在Servlet的生命周期中仅被调用一次,用于进行一次性初始化操作。 -
service()方法:用于处理客户端请求并生成响应。根据HTTP请求的类型,该方法可能会将请求转发给doGet()或doPost()方法。如果是GET请求,将调用doGet()方法;如果是POST请求,将调用doPost()方法。service()方法能够处理这两种类型的请求,若要自定义处理逻辑,需要在Servlet中重写该方法。该方法接受两个参数:ServletRequest对象(用于处理客户端请求)和ServletResponse对象(用于向客户端写入响应),这两个对象由Servlet容器传递给它。 -
destroy()方法:在Servlet被卸载之前,由Servlet容器调用,可用于执行清理活动,如关闭数据库连接。
2.2 第一个Servlet示例
下面是一个简单的Servlet示例,用于向客户端输出内容:
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class FirstServlet extends HttpServlet {
public void service(ServletRequest req, ServletResponse res) throws ServletException,IOException {
res.setContentType("text/plain");
PrintWriter pw = res.getWriter();
pw.println("My First Servlet is running");
}
}
代码解释
-
L1 - L3
:为了创建一个HttpServlet,需要导入
javax.servlet.*、javax.servlet.http.*和java.io.*包。 -
L4
:
FirstServlet类必须是公共类,并且继承自HttpServlet,因为客户端和服务器之间使用HTTP协议进行通信,所以要处理客户端的HTTP请求并生成HTTP响应,就需要创建一个HttpServlet。 -
L5
:重写了
service()方法,它接受ServletRequest和ServletResponse两个参数。客户端的整个请求被封装在ServletRequest对象(如HTTP、FTP)中,并由Servlet容器与ServletResponse对象一起传递给service()方法。ServletResponse对象用于向客户端发送响应(通常是HTML响应),该方法可能会抛出ServletException和IOException。 -
L6
:在向客户端发送任何数据之前,需要使用
res.setContentType("text/plain")方法指定要发送给客户端的数据类型,即设置MIME类型。在本示例中,Servlet传输的是纯文本,所以MIME类型是text/plain;如果要发送HTML(网页),MIME类型则是text/html。 -
L7 - L8
:使用
res对象的getWriter()方法获取一个PrintWriter对象,该方法可能会抛出IOException,因此在service()方法的定义中使用throws子句声明了该异常。使用PrintWriter对象的println方法将内容写入客户端,println方法的字符串参数会原样写入客户端。
2.3 运行Servlet的步骤
2.3.1 编译Servlet
编译Servlet类时,需要在类路径中包含
servlet-api.jar
文件,可在命令提示符下执行以下命令:
set classpath = %classpath%; C:\Apache\Tomcat 7.0\lib\servlet-api.jar;
或者编辑环境变量
classpath
,并将上述路径追加到其中。
2.3.2 安装Tomcat 7.0并执行Servlet和JSP
我们使用Tomcat 7.0.40来运行Servlet和JSP。可以从Apache Tomcat网站(如
apache-tomcat-7.0.40
)下载Web服务器安装程序。安装过程非常简单,只需双击安装程序即可开始安装。安装时需要指定Web服务器的安装路径(如果不指定,将安装在计算机的程序文件目录中)。该服务器会作为服务安装在计算机上,可以通过打开计算机的控制面板并点击“管理工具”来手动启动/停止该服务。同时,建议设置以下两个环境变量:
-
JAVA_HOME = c:\program files\java\jdk1.6.0_01
(JDK的基本目录)
-
CATALINA_HOME = c:\Apache\Tomcat 5.0
(Tomcat的基本目录)
要测试服务器是否实际运行,可打开浏览器,在地址栏中输入
http://localhost:8080
。
2.3.3 将编译后的Servlet类放置到Tomcat的适当目录
我们在
webapps
目录下创建了名为
myproj
的目录,用于放置创建的Servlet。所有Servlet类文件都放在
classes
目录中,
WEB-INF
目录中存在
web.xml
文件。以下是一个运行
FirstServlet.class
的示例
web.xml
文件:
<?xml version = "1.0" encoding = "ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<!-- Define servlets that are included in the example application -->
<servlet>
<servlet-name>FirstServlet</servlet-name>
<servlet-class>FirstServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FirstServlet</servlet-name>
<url-pattern>/servlet/FirstServlet</url-pattern>
</servlet-mapping>
</web-app>
web.xml
文件作为Servlet的部署描述符,它指定了Servlet的名称和URL映射。具体来说,它将Servlet类文件与一个名称关联起来,并为Servlet定义了一个URL映射。每次在
classes
目录中添加新的Servlet类时,都需要编辑该文件,为每个Servlet添加
<servlet>
和
<servlet-mapping>
标签及其子标签,以指定调用Servlet的名称和URL。例如,
<servlet>
标签指定
FirstServlet.class
将被称为
FirstServlet
,
<servlet-mapping>
标签指定访问该Servlet的URL为
http://localhost:8080/myproj/servlet/FirstServlet
。在Internet Explorer中运行该Servlet,将显示相应的输出。
2.4 读取客户端数据
客户端数据通过HTTP协议的两种方法(GET和POST)从客户端浏览器发送到服务器。这两种方法在从客户端向服务器发送数据的方式上有所不同:
-
GET方法
:将数据附加到处理请求的Servlet的URL后面,并将其传递给服务器。这种方法的缺点是URL的长度是固定的,这限制了可以传输到服务器的数据量,而且发送到服务器的任何数据都以明文形式可见。
-
POST方法
:通过将数据作为HTTP头格式的一部分发送到服务器,而不是将其附加到URL,克服了GET方法的这些限制。
以下是用于从客户端请求中获取值的方法:
| 方法 | 描述 |
| — | — |
|
String getParameter(String n)
| 用于返回与给定名称对应的的值,名称作为参数(
String n
)指定,“name”是HTML中控件的名称,使用该方法需要知道名称。 |
|
Enumeration getParameterNames()
| 当我们不总是知道请求中的所有名称时,该方法返回与请求关联的所有名称的枚举。 |
|
String[] getParameterValues (String n)
| 返回与单个名称关联的所有值的字符串数组,例如爱好。 |
2.4.1 HTML表单示例
以下是一个用于向服务器发送表单数据的HTML文件示例:
<html>
<head><title> form data </title></head>
<body>
<center>
<h1><U> Registration Form </u></h1>
<form method = get action = "servlet/ReadData">
Name <input type = text name = fname><br>
Address <input type = text name = add><br>
User id <input type = text name = uid><br>
Password <input type = password name = pass><br>
Gender:
male<input type = radio name = gender value = male>
female<input type = radio name = gender value = female><br>
Hobbies:
Dancing <input type = checkbox name = hobbies value = dance>
Music <input type = checkbox name = hobbies value = music>
Travel <input type = checkbox name = hobbies value = travel>
<br>
<input type = submit>
<input type = reset>
</form>
</center>
</body>
</html>
该HTML页面包含一个表单,表单标签有两个属性:
method
和
action
。
method
属性用于指定向服务器发送数据的方法(如GET和POST),
action
属性用于指定处理请求的Servlet的URL。表单包含文本字段(如姓名、地址和用户ID)、密码字段、单选按钮和复选框,这些字段通过
input
标签创建,
input
标签有
type
和
name
属性,
type
指定输入字段的类型,
name
属性用于给控件命名,该名称将作为
getParameter(String n)
方法的参数,用于在Servlet中获取其值。以下是
input
标签
type
属性的一些可能值及其描述:
|
type
属性值 | 描述 |
| — | — |
|
type = text
| 创建一个文本字段。 |
|
type = submit
| 创建一个提交按钮,点击该按钮时,将表单中的数据发送到表单标签
action
属性指定的Servlet,发送方式由
method
属性指定。 |
|
type = reset
| 创建一个重置按钮,用于重置表单中的所有字段和选择。 |
|
type = password
| 创建一个密码字段,该字段中的字符以点号显示。 |
|
type = button
| 创建一个普通按钮,点击该按钮不会有任何动作(可使用JavaScript进行事件处理)。 |
|
type = radio
| 创建一个单选按钮(单选)。 |
|
type = checkbox
| 创建一个复选框(多选)。 |
点击提交按钮时,URL将如下所示:
http://localhost:8080/myproj/ReadServlet?fname = peter&add = London&uid = pet_007&pass = jennifer&gender = male&hobbies = music&hobbies = dancing
?
运算符将数据与地址分隔开,
&
运算符将一个名称/值对与另一个分隔开。
2.4.2 提取客户端请求数据的Servlet示例
以下是用于处理客户端请求并生成响应的Servlet示例,该Servlet将所有数据回显给客户端:
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
public class ReadData extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
res.setContentType("text/html");
PrintWriter out = res.getWriter();
Enumeration e = req.getParameterNames();
while(e.hasMoreElements()) {
String name = (String)e.nextElement();
String[] values = req.getParameterValues(name);
for(int i = 0; i < values.length; i++) {
out.println("<html><head><title> client data</title></head>");
out.println("<body><B>");
out.println(name + " : <i>" +values [i] + "</i><br>");
out.println("</body></html>");
}
}
}
public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
doGet(req,res);
}
}
代码解释
-
L1
:除了其他包外,还导入了
java.util包,原因将在下面的解释中说明。 -
L2
:创建了一个公共的Servlet类
ReadServlet,该类继承自HttpServlet,因为我们处理的是HTTP请求和HTTP响应。 -
L3
:重写了
doGet方法,用于处理来自客户端的GET请求。该方法接受两个参数:HttpServletRequest(仅用于HTTP客户端请求)和HttpServletResponse(用于向客户端发送HTTP响应)。与service方法类似,该方法也可能抛出ServletException和IOException。 -
L6
:通过
req对象调用getParameterNames()方法,该方法从请求对象中的名称/值对中提取所有名称,并将它们作为名称的枚举返回。枚举是一个集合接口,它是java.util的一部分,这就是为什么在L1中导入了该包。 - L7 - L13 :对枚举中的每个名称重复执行以下操作。
-
L8
:从枚举中提取下一个名称,并将其存储在字符串变量
name中。 -
L9
:
req.getParameterValues(name)返回与该名称关联的所有值的字符串数组。 -
L10 - L13
:使用
for循环遍历数组中的所有值。在println方法的引号内写入HTML标签,以将HTML发送到客户端的浏览器。名称以粗体显示,值以粗体和斜体显示。 -
L14 - L15
:重写了
doPost方法,它几乎与doGet方法完全相同。在doPost方法中调用doGet方法,这样Servlet就能够处理GET和POST请求,无需担心请求是GET请求还是POST请求。
在运行该示例之前,请确保
web.xml
文件中存在Servlet名称和映射,
myproj
Web应用程序的
web.xml
文件中必须包含以下标签:
<servlet>
<servlet-name>ReadData</servlet-name>
<servlet-class>ReadData</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ReadData</servlet-name>
<url-pattern>/servlet/ReadData</url-pattern>
</servlet-mapping>
2.5 HTTP重定向
HTTP重定向是一种将用户重定向到Internet上另一个位置的方法。例如,当你的网站有了新的域名,但所有用户都未被告知时,他们仍会访问旧的URL。HTTP重定向可以告知客户端浏览器新的URL,所有到达旧URL的请求都会被重定向到新URL。
3. HTTP重定向的实现方式
在Servlet中实现HTTP重定向通常有两种方式,下面分别进行介绍。
3.1 使用
response.sendRedirect()
方法
这是最常用的实现HTTP重定向的方法,以下是一个简单的示例代码:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class RedirectServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置重定向的URL
String newUrl = "http://newdomain.com";
// 执行重定向
response.sendRedirect(newUrl);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
代码解释
-
在
doGet方法中,首先定义了要重定向的新URL,然后调用response.sendRedirect(newUrl)方法将客户端重定向到指定的URL。 -
doPost方法调用了doGet方法,这样该Servlet就能处理GET和POST请求。
配置
web.xml
文件
在
web.xml
文件中配置该Servlet,示例如下:
<servlet>
<servlet-name>RedirectServlet</servlet-name>
<servlet-class>RedirectServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RedirectServlet</servlet-name>
<url-pattern>/servlet/RedirectServlet</url-pattern>
</servlet-mapping>
当客户端访问
http://localhost:8080/myproj/servlet/RedirectServlet
时,就会被重定向到
http://newdomain.com
。
3.2 使用
response.setStatus()
和
response.setHeader()
方法
这种方式相对复杂一些,但可以更灵活地控制重定向的状态码和响应头信息。示例代码如下:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CustomRedirectServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置重定向的状态码
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
// 设置重定向的URL
response.setHeader("Location", "http://newdomain.com");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
代码解释
-
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY)将响应的状态码设置为301,表示永久重定向。 -
response.setHeader("Location", "http://newdomain.com")设置重定向的目标URL。
配置
web.xml
文件
同样,需要在
web.xml
文件中配置该Servlet:
<servlet>
<servlet-name>CustomRedirectServlet</servlet-name>
<servlet-class>CustomRedirectServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CustomRedirectServlet</servlet-name>
<url-pattern>/servlet/CustomRedirectServlet</url-pattern>
</servlet-mapping>
3.3 两种方式的比较
| 方式 | 优点 | 缺点 |
|---|---|---|
response.sendRedirect()
| 代码简单,使用方便,自动处理状态码和响应头信息 | 只能进行302临时重定向,无法灵活控制状态码 |
response.setStatus()
和
response.setHeader()
| 可以灵活控制重定向的状态码和响应头信息 | 代码相对复杂,需要手动设置状态码和响应头 |
4. Cookie的使用
Cookie是在客户端浏览器和服务器之间传递的小段数据,用于存储用户的信息,如用户偏好、登录状态等。以下是一个简单的Cookie使用示例。
4.1 创建和发送Cookie
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CookieDemo extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 创建一个Cookie对象
Cookie cookie = new Cookie("username", "JohnDoe");
// 设置Cookie的有效期(单位:秒)
cookie.setMaxAge(3600);
// 将Cookie添加到响应中
response.addCookie(cookie);
// 设置响应内容类型
response.setContentType("text/html");
// 获取输出流
java.io.PrintWriter out = response.getWriter();
// 输出提示信息
out.println("<html><body>");
out.println("Cookie has been set.");
out.println("</body></html>");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
代码解释
-
Cookie cookie = new Cookie("username", "JohnDoe")创建了一个名为username,值为JohnDoe的Cookie对象。 -
cookie.setMaxAge(3600)设置Cookie的有效期为1小时(3600秒)。 -
response.addCookie(cookie)将Cookie添加到响应中,发送给客户端。
配置
web.xml
文件
<servlet>
<servlet-name>CookieDemo</servlet-name>
<servlet-class>CookieDemo</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CookieDemo</servlet-name>
<url-pattern>/servlet/CookieDemo</url-pattern>
</servlet-mapping>
4.2 读取Cookie
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ReadCookie extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取客户端发送的所有Cookie
Cookie[] cookies = request.getCookies();
// 设置响应内容类型
response.setContentType("text/html");
// 获取输出流
java.io.PrintWriter out = response.getWriter();
// 输出HTML头部
out.println("<html><body>");
if (cookies != null) {
for (Cookie cookie : cookies) {
if ("username".equals(cookie.getName())) {
out.println("Username: " + cookie.getValue());
}
}
} else {
out.println("No cookies found.");
}
// 输出HTML尾部
out.println("</body></html>");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
代码解释
-
Cookie[] cookies = request.getCookies()获取客户端发送的所有Cookie。 -
通过遍历
cookies数组,找到名为username的Cookie,并输出其值。
配置
web.xml
文件
<servlet>
<servlet-name>ReadCookie</servlet-name>
<servlet-class>ReadCookie</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ReadCookie</servlet-name>
<url-pattern>/servlet/ReadCookie</url-pattern>
</servlet-mapping>
4.3 删除Cookie
要删除一个Cookie,可以将其有效期设置为0,示例代码如下:
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class DeleteCookie extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取客户端发送的所有Cookie
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if ("username".equals(cookie.getName())) {
// 设置Cookie的有效期为0
cookie.setMaxAge(0);
// 将修改后的Cookie添加到响应中
response.addCookie(cookie);
}
}
}
// 设置响应内容类型
response.setContentType("text/html");
// 获取输出流
java.io.PrintWriter out = response.getWriter();
// 输出提示信息
out.println("<html><body>");
out.println("Cookie has been deleted.");
out.println("</body></html>");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
配置
web.xml
文件
<servlet>
<servlet-name>DeleteCookie</servlet-name>
<servlet-class>DeleteCookie</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DeleteCookie</servlet-name>
<url-pattern>/servlet/DeleteCookie</url-pattern>
</servlet-mapping>
5. 总结
本文详细介绍了Java编程中Servlet的相关知识,包括事务处理中的Savepoint、Servlet的生命周期、创建和运行Servlet的步骤、读取客户端数据、HTTP重定向以及Cookie的使用等内容。通过实际的代码示例和详细的解释,帮助读者更好地理解和掌握这些技术。
5.1 关键知识点回顾
- Savepoint :用于在事务中回滚到指定的保存点,避免因某些操作失败而导致整个事务回滚。
-
Servlet生命周期
:包括
init()、service()和destroy()方法,分别用于初始化、处理请求和清理资源。 -
运行Servlet步骤
:包括编译Servlet、安装Tomcat、配置
web.xml文件等。 -
读取客户端数据
:通过
getParameter()、getParameterNames()和getParameterValues()方法获取客户端请求中的数据。 -
HTTP重定向
:可以使用
response.sendRedirect()或response.setStatus()和response.setHeader()方法实现。 - Cookie使用 :包括创建、读取和删除Cookie,用于在客户端和服务器之间传递数据。
5.2 后续学习建议
- 深入学习Servlet的高级特性,如过滤器、监听器等。
- 结合数据库操作,实现更复杂的Web应用程序。
- 学习JSP(Java Server Pages)技术,提高页面开发效率。
希望本文能为读者在Java Web开发方面提供有价值的参考,帮助大家更好地掌握Servlet相关知识和技能。
661

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



