Servlets - 快速指南
Servlets - Overview
什么是Servlets?
Java Servlet是在Web或应用程序服务器上运行的程序,充当来自Web浏览器或其他HTTP客户端的请求与HTTP服务器上的数据库或应用程序之间的中间层。
使用Servlet,您可以通过网页表单收集用户的输入,从数据库或其他来源显示记录,以及动态创建网页。
Java Servlet通常与使用通用网关接口(CGI)实现的程序具有相同的用途。 但与CGI相比,Servlet具有几个优点。
性能明显更好。
Servlet在Web服务器的地址空间内执行。 没有必要创建一个单独的进程来处理每个客户端请求。
Servlet是独立于平台的,因为它们是用Java编写的。
服务器上的Java安全管理器强制实施一组限制以保护服务器计算机上的资源。 所以servlet是值得信赖的。
servlet可以使用Java类库的完整功能。 它可以通过您已经看到的套接字和RMI机制与applet,数据库或其他软件进行通信。
Servlets架构
下图显示了Web应用程序中Servlet的位置。
Servlets任务
Servlet执行以下主要任务 -
读取客户端(浏览器)发送的显式数据。 这包括网页上的HTML表单,也可能来自applet或自定义HTTP客户端程序。
读取客户端(浏览器)发送的隐式HTTP请求数据。 这包括浏览器理解的cookie,媒体类型和压缩方案等。
处理数据并生成结果。 此过程可能需要与数据库通信,执行RMI或CORBA调用,调用Web服务或直接计算响应。
将显式数据(即文档)发送到客户端(浏览器)。 该文档可以以多种格式发送,包括文本(HTML或XML),二进制(GIF图像),Excel等。
将隐式HTTP响应发送到客户端(浏览器)。 这包括告诉浏览器或其他客户端返回什么类型的文档(例如,HTML),设置cookie和缓存参数以及其他此类任务。
Servlets包
Java Servlet是由Web服务器运行的Java类,它具有支持Java Servlet规范的解释器。
Servlet可以使用javax.servlet和javax.servlet.http包创建,这些包是Java企业版的标准部分,是支持大型开发项目的Java类库的扩展版本。
这些类实现了Java Servlet和JSP规范。 在编写本教程时,版本是Java Servlet 2.5和JSP 2.1。
Java servlet的创建和编译与任何其他Java类一样。 安装servlet包并将它们添加到计算机的Classpath后,可以使用JDK的Java编译器或任何其他当前编译器编译servlet。
接下来是什么 (What is Next?)
我会带你一步一步地设置你的环境,从Servlets开始。 因此,使用Servlet可以将皮带系好。 我相信你会非常喜欢这个教程。
Servlets - Environment Setup
开发环境是您开发Servlet,测试它们并最终运行它们的地方。
与任何其他Java程序一样,您需要使用Java编译器javac编译servlet,并在编译servlet应用程序之后,将其部署在已配置的环境中以进行测试和运行。
此开发环境设置包括以下步骤 -
设置Java Development Kit
此步骤涉及下载Java软件开发工具包(SDK)的实现并适当地设置PATH环境变量。
您可以从Oracle的Java站点下载SDK - Java SE下载 。
下载Java实现后,请按照给出的说明安装和配置设置。 最后设置PATH和JAVA_HOME环境变量来引用包含java和javac的目录,通常分别是java_install_dir/bin和java_install_dir。
如果您运行的是Windows并在C:\_ jdk1.8.0_65中安装了SDK,则应将以下行放在C:\autoexec.bat文件中。
set PATH = C:\jdk1.8.0_65\bin;%PATH%
set JAVA_HOME = C:\jdk1.8.0_65
或者,在Windows NT/2000/XP上,您也可以右键单击“我的电脑”,选择“属性”,然后选择“高级”,再选择“环境变量”。 然后,您将更新PATH值并按OK按钮。
在Unix(Solaris,Linux等)上,如果SDK安装在/usr/local/jdk1.8.0_65中并且您使用C shell,则将以下内容放入.cshrc文件中。
setenv PATH /usr/local/jdk1.8.0_65/bin:$PATH
setenv JAVA_HOME /usr/local/jdk1.8.0_65
或者,如果您使用集成开发环境(IDE)(如Borland JBuilder,Eclipse,IntelliJ IDEA或Sun ONE Studio),请编译并运行一个简单程序以确认IDE知道您在何处安装Java。
设置Web服务器 - Tomcat
市场上有许多支持servlet的Web服务器。 一些Web服务器可以免费下载,Tomcat就是其中之一。
Apache Tomcat是Java Servlet和Java Server Pages技术的开源软件实现,可以作为测试servlet的独立服务器,并可以与Apache Web Server集成。 以下是在您的计算机上设置Tomcat的步骤 -
从https://tomcat.apache.org/下载最新版本的Tomcat。
下载安装后,将二进制分发包解压到一个方便的位置。 例如,在Windows上的C:\apache-tomcat-8.0.28或Linux/Unix上的/usr/local/apache-tomcat-8.0.289中,创建指向这些位置的CATALINA_HOME环境变量。
可以通过在Windows机器上执行以下命令来启动Tomcat -
%CATALINA_HOME%\bin\startup.bat
or
C:\apache-tomcat-8.0.28\bin\startup.bat
可以通过在Unix(Solaris,Linux等)机器上执行以下命令来启动Tomcat -
$CATALINA_HOME/bin/startup.sh
or
/usr/local/apache-tomcat-8.0.28/bin/startup.sh
启动后,访问http://localhost:8080/将可以使用Tomcat附带的默认Web应用程序。 如果一切都很好,那么它应该显示以下结果 -
有关配置和运行Tomcat的更多信息,请参阅此处包含的文档以及Tomcat网站 - http://tomcat.apache.org
可以通过在Windows机器上执行以下命令来停止Tomcat -
C:\apache-tomcat-8.0.28\bin\shutdown
可以通过在Unix(Solaris,Linux等)机器上执行以下命令来停止Tomcat -
/usr/local/apache-tomcat-8.0.28/bin/shutdown.sh
设置CLASSPATH
由于servlet不是Java Platform,Standard Edition的一部分,因此必须为编译器识别servlet类。
如果您运行的是Windows,则需要在C:\autoexec.bat文件中添加以下行。
set CATALINA = C:\apache-tomcat-8.0.28
set CLASSPATH = %CATALINA%\common\lib\servlet-api.jar;%CLASSPATH%
或者,在Windows NT/2000/XP上,您可以转到“我的电脑” - >“属性” - >“高级” - >“环境变量”。 然后,您将更新CLASSPATH值并按“确定”按钮。
在Unix(Solaris,Linux等)上,如果您使用的是C shell,则可以将以下行放入.cshrc文件中。
setenv CATALINA = /usr/local/apache-tomcat-8.0.28
setenv CLASSPATH $CATALINA/common/lib/servlet-api.jar:$CLASSPATH
NOTE - 假设您的开发目录是C:\ServletDevel(Windows)或/ usr/ServletDevel(Unix),那么您需要在CLASSPATH中添加这些目录,方法与上面添加的类似。
Servlets - Life Cycle
servlet生命周期可以定义为从创建到销毁的整个过程。 以下是servlet遵循的路径。
通过调用init()方法初始化servlet。
servlet调用service()方法来处理客户端的请求。
通过调用destroy()方法终止servlet。
最后,servlet被JVM的垃圾收集器垃圾收集。
现在让我们详细讨论生命周期方法。
The init() Method
init方法只调用一次。 只有在创建servlet时才会调用它,之后不会调用任何用户请求。 因此,它用于一次性初始化,就像applet的init方法一样。
servlet通常在用户首次调用与servlet对应的URL时创建,但您也可以指定在首次启动服务器时加载servlet。
当用户调用servlet时,会创建每个servlet的单个实例,每个用户请求都会生成一个新线程,该线程将根据需要传递给doGet或doPost。 init()方法只是创建或加载一些将在servlet的整个生命周期中使用的数据。
init方法定义如下所示 -
public void init() throws ServletException {
// Initialization code...
}
The service() Method
service()方法是执行实际任务的主要方法。 servlet容器(即Web服务器)调用service()方法来处理来自客户端(浏览器)的请求,并将格式化的响应写回客户端。
每次服务器收到servlet请求时,服务器都会生成一个新线程并调用服务。 service()方法检查HTTP请求类型(GET,POST,PUT,DELETE等),并根据需要调用doGet,doPost,doPut,doDelete等方法。
这是这种方法的签名 -
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
}
service()方法由容器调用,service方法根据需要调用doGet,doPost,doPut,doDelete等方法。 因此,您与service()方法无关,但您可以覆盖doGet()或doPost(),具体取决于您从客户端收到的请求类型。
doGet()和doPost()是每个服务请求中最常用的方法。 这是这两种方法的签名。
The doGet() Method
GET请求来自对URL的正常请求或来自未指定METHOD的HTML表单,并且应由doGet()方法处理。
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Servlet code
}
The doPost() Method
POST请求来自HTML表单,该表单专门将POST列为METHOD,它应该由doPost()方法处理。
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Servlet code
}
The destroy() Method
destroy()方法仅在servlet生命周期结束时调用一次。 此方法使您的servlet有机会关闭数据库连接,暂停后台线程,写入cookie列表或命中磁盘计数,以及执行其他此类清理活动。
调用destroy()方法后,servlet对象被标记为垃圾回收。 destroy方法定义如下所示 -
public void destroy() {
// Finalization code...
}
建筑图
下图描绘了典型的servlet生命周期场景。
首先,将发送到服务器的HTTP请求委托给servlet容器。
servlet容器在调用service()方法之前加载servlet。
然后servlet容器通过生成多个线程来处理多个请求,每个线程执行servlet的单个实例的service()方法。
Servlets - Examples
Servlet是服务HTTP请求并实现javax.servlet.Servlet接口的Java类。 Web应用程序开发人员通常编写扩展javax.servlet.http.HttpServlet的servlet,这是一个实现Servlet接口的抽象类,专门用于处理HTTP请求。
示例代码 (Sample Code)
以下是显示Hello World的servlet示例的示例源代码结构 -
// Import required java libraries
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
// Extend HttpServlet class
public class HelloWorld extends HttpServlet {
private String message;
public void init() throws ServletException {
// Do required initialization
message = "Hello World";
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Set response content type
response.setContentType("text/html");
// Actual logic goes here.
PrintWriter out = response.getWriter();
out.println("<h1>" + message + "</h1>");
}
public void destroy() {
// do nothing.
}
}
编译Servlet
让我们创建一个名为HelloWorld.java的文件,其代码如上所示。 将此文件放在C:\ServletDevel(在Windows中)或/ usr/ServletDevel(在Unix中)。 必须先将此路径位置添加到CLASSPATH,然后再继续。
假设您的环境设置正确,请进入ServletDevel目录并编译HelloWorld.java,如下所示 -
$ javac HelloWorld.java
如果servlet依赖于任何其他库,则还必须在CLASSPATH上包含这些JAR文件。 我只包含了servlet-api.jar JAR文件,因为我没有在Hello World程序中使用任何其他库。
此命令行使用Sun Microsystems Java软件开发工具包(JDK)附带的内置javac编译器。 要使此命令正常工作,您必须在PATH环境变量中包含您正在使用的Java SDK的位置。
如果一切顺利,上面的编译将在同一目录中生成HelloWorld.class文件。 下一节将解释如何在生产中部署已编译的servlet。
Servlet部署
默认情况下,servlet应用程序位于路径
如果您具有com.myorg.MyServlet的完全限定类名,则此servlet类必须位于WEB-INF/classes/com/myorg/MyServlet.class中。
现在,让我们将HelloWorld.class复制到
<servlet>
<servlet-name>HelloWorld</servlet-name>
<servlet-class>HelloWorld</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloWorld</servlet-name>
<url-pattern>/HelloWorld</url-pattern>
</servlet-mapping>
上面的条目将在web.xml文件中提供的
你差不多完成了,现在让我们使用
Servlets - Form Data
当您需要将某些信息从浏览器传递到Web服务器并最终传递到后端程序时,您必须遇到很多情况。 浏览器使用两种方法将此信息传递给Web服务器。 这些方法是GET方法和POST方法。
GET方法
GET方法发送附加到页面请求的编码用户信息。 页面和编码信息由?分隔? (问号)符号如下 -
http://www.test.com/hello?key1 = value1&key2 = value2
GET方法是将信息从浏览器传递到Web服务器的默认方法,它会生成一个长字符串,显示在浏览器的Location:框中。 如果您要将密码或其他敏感信息传递给服务器,请勿使用GET方法。 GET方法有大小限制:请求字符串中只能使用1024个字符。
此信息使用QUERY_STRING标头传递,可通过QUERY_STRING环境变量访问,Servlet使用doGet()方法处理此类请求。
POST Method
将信息传递给后端程序的一般更可靠的方法是POST方法。 这以与GET方法完全相同的方式打包信息,而不是在一个?之后将其作为文本字符串发送? (问号)在URL中将其作为单独的消息发送。 此消息以标准输入的形式提供给后端程序,您可以解析并用于处理。 Servlet使用doPost()方法处理这种类型的请求。
使用Servlet读取表单数据
Servlet根据具体情况使用以下方法自动处理表单数据解析 -
getParameter() - 您调用request.getParameter()方法来获取表单参数的值。
getParameterValues() - 如果参数出现多次并返回多个值(例如复选框getParameterValues() ,则调用此方法。
getParameterNames() - 如果需要当前请求中所有参数的完整列表,请调用此方法。
使用URL获取GET方法示例
这是一个简单的URL,它将使用GET方法将两个值传递给HelloForm程序。
http://localhost:8080/HelloForm?first_name = ZARA&last_name = ALI下面给出了HelloForm.java servlet程序来处理Web浏览器给出的输入。 我们将使用getParameter()方法,这使得访问传递的信息变得非常容易 -
// Import required java libraries
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
// Extend HttpServlet class
public class HelloForm extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String title = "Using GET Method to Read Form Data";
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor = \"#f0f0f0\">\n" +
"<h1 align = \"center\">" + title + "</h1>\n" +
"<ul>\n" +
" <li><b>First Name</b>: "
+ request.getParameter("first_name") + "\n" +
" <li><b>Last Name</b>: "
+ request.getParameter("last_name") + "\n" +
"</ul>\n" +
"</body>" +
"</html>"
);
}
}
假设您的环境设置正确,请按如下方式编译HelloForm.java -
$ javac HelloForm.java
如果一切顺利,上面的编译将产生HelloForm.class文件。 接下来,您必须在“Tomcat-installationdirectory”/ webapps/ROOT/WEB-INF/classes中复制此类文件,并在“Tomcat-installation-directory”/ webapps/ROOT/WEB-中的web.xml文件中创建以下条目: INF/
<servlet>
<servlet-name>HelloForm</servlet-name>
<servlet-class>HelloForm</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloForm</servlet-name>
<url-pattern>/HelloForm</url-pattern>
</servlet-mapping>
现在在浏览器的Location:框中键入http://localhost:8080/HelloForm?first_name=ZARA&last_name=ALI ,并确保在浏览器中触发上述命令之前已经启动了tomcat服务器。 这将产生以下结果 -
<h1 align="center">Using GET Method to Read Form Data</h1>
- First Name :ZARA
- Last Name :ALI
使用表格获取方法示例
这是一个使用HTML FORM和提交按钮传递两个值的简单示例。 我们将使用相同的Servlet HelloForm来处理此输入。
<html>
<body>
<form action = "HelloForm" 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的本地计算机上查看结果。 根据提供的输入,它将生成与上例中提到的类似的结果。
使用表单的POST方法示例
让我们在上面的servlet中做一点修改,这样它就可以处理GET和POST方法。 下面是HelloForm.java servlet程序,用于处理Web浏览器使用GET或POST方法给出的输入。
// Import required java libraries
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
// Extend HttpServlet class
public class HelloForm extends HttpServlet {
// Method to handle GET method request.
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String title = "Using GET Method to Read Form Data";
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " +
"transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor = \"#f0f0f0\">\n" +
"<h1 align = \"center\">" + title + "</h1>\n" +
"<ul>\n" +
" <li><b>First Name</b>: "
+ request.getParameter("first_name") + "\n" +
" <li><b>Last Name</b>: "
+ request.getParameter("last_name") + "\n" +
"</ul>\n" +
"</body>"
"</html>"
);
}
// Method to handle POST method request.
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
现在编译和部署上面的Servlet并使用Hello方法使用POST方法测试它,如下所示 -
<html>
<body>
<form action = "HelloForm" 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>
以下是上述表单的实际输出,尝试输入名字和姓氏,然后单击“提交”按钮以在运行tomcat的本地计算机上查看结果。
基于所提供的输入,它将产生与上述示例中提到的类似的结果。
将Checkbox数据传递给Servlet程序
如果需要选择多个选项,则使用复选框。
下面是示例HTML代码CheckBox.htm,用于包含两个复选框的表单
<html>
<body>
<form action = "CheckBox" 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>
此代码的结果如下所示
下面给出了CheckBox.java servlet程序,用于处理Web浏览器为复选框按钮提供的输入。
// Import required java libraries
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
// Extend HttpServlet class
public class CheckBox extends HttpServlet {
// Method to handle GET method request.
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String title = "Reading Checkbox Data";
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor = \"#f0f0f0\">\n" +
"<h1 align = \"center\">" + title + "</h1>\n" +
"<ul>\n" +
" <li><b>Maths Flag : </b>: "
+ request.getParameter("maths") + "\n" +
" <li><b>Physics Flag: </b>: "
+ request.getParameter("physics") + "\n" +
" <li><b>Chemistry Flag: </b>: "
+ request.getParameter("chemistry") + "\n" +
"</ul>\n" +
"</body>"
"</html>"
);
}
// Method to handle POST method request.
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
对于上面的例子,它会显示以下结果 -
<h1 align="center">Reading Checkbox Data</h1>
- Maths Flag : ::开
- Physics Flag: :: null
- Chemistry Flag: :上
阅读所有表格参数
以下是使用HttpServletRequest的getParameterNames()方法读取所有可用表单参数的通用示例。 此方法返回一个Enumeration,其中包含未指定顺序的参数名称
一旦我们有了Enumeration,我们就可以通过标准方式循环Enumeration,使用hasMoreElements()方法确定何时停止并使用nextElement()方法获取每个参数名称。
// Import required java libraries
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
// Extend HttpServlet class
public class ReadParams extends HttpServlet {
// Method to handle GET method request.
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String title = "Reading All Form Parameters";
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor = \"#f0f0f0\">\n" +
"<h1 align = \"center\">" + title + "</h1>\n" +
"<table width = \"100%\" border = \"1\" align = \"center\">\n" +
"<tr bgcolor = \"#949494\">\n" +
"<th>Param Name</th>"
"<th>Param Value(s)</th>\n"+
"</tr>\n"
);
Enumeration paramNames = request.getParameterNames();
while(paramNames.hasMoreElements()) {
String paramName = (String)paramNames.nextElement();
out.print("<tr><td>" + paramName + "</td>\n<td>");
String[] paramValues = request.getParameterValues(paramName);
// Read single valued data
if (paramValues.length == 1) {
String paramValue = paramValues[0];
if (paramValue.length() == 0)
out.println("<i>No Value</i>");
else
out.println(paramValue);
} else {
// Read multiple valued data
out.println("<ul>");
for(int i = 0; i < paramValues.length; i++) {
out.println("<li>" + paramValues[i]);
}
out.println("</ul>");
}
}
out.println("</tr>\n</table>\n</body></html>");
}
// Method to handle POST method request.
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
现在,使用以下表单尝试上面的servlet -
<html>
<body>
<form action = "ReadParams" 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>
现在使用上面的表单调用servlet会产生以下结果 -
<h1 align="center">Reading All Form Parameters</h1>
参数名称 | 参数价值 |
---|---|
maths | on |
chemistry | on |
您可以尝试使用上面的servlet来读取任何其他表单的数据,这些数据包含其他对象,如文本框,单选按钮或下拉框等。
Servlets - Client HTTP Request
当浏览器请求网页时,它会向Web服务器发送大量信息,这些信息无法直接读取,因为此信息作为HTTP请求标头的一部分传播。 您可以检查HTTP协议以获取更多信息。
以下是来自浏览器端的重要标题信息,您将在网络编程中经常使用 -
Sr.No. | 标题和说明 |
---|---|
1 | Accept 此标头指定浏览器或其他客户端可以处理的MIME类型。 image/png或image/jpeg是两种最常见的可能性。 |
2 | Accept-Charset 此标头指定浏览器可用于显示信息的字符集。 例如ISO-8859-1。 |
3 | Accept-Encoding 此标头指定浏览器知道如何处理的编码类型。 gzip或compress值是两种最常见的可能性。 |
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,这意味着Not Modified标头。 |
11 | If-Unmodified-Since 此标头与If-Modified-Since相反; 它指定仅当文档早于指定日期时操作才会成功。 |
12 | Referer 此标头指示引用网页的URL。 例如,如果您在网页1并单击指向网页2的链接,则当浏览器请求网页2时,网页1的URL将包含在Referrer标头中。 |
13 | User-Agent 此标头标识发出请求的浏览器或其他客户端,可用于将不同内容返回到不同类型的浏览器。 |
读取HTTP标头的方法
有以下方法可用于读取servlet程序中的HTTP标头。 这些方法可用于HttpServletRequest对象
Sr.No. | 方法和描述 |
---|---|
1 | Cookie[] getCookies() 返回一个数组,其中包含客户端使用此请求发送的所有Cookie对象。 |
2 | Enumeration getAttributeNames() 返回包含此请求可用属性名称的Enumeration。 |
3 | Enumeration getHeaderNames() 返回此请求包含的所有标头名称的枚举。 |
4 | Enumeration getParameterNames() 返回String对象的Enumeration,其中包含此请求中包含的参数的名称 |
5 | HttpSession getSession() 返回与此请求关联的当前会话,或者如果请求没有会话,则创建一个会话。 |
6 | HttpSession getSession(boolean create) 返回与此请求关联的当前HttpSession,如果没有当前会话且create的值为true,则返回新会话。 |
7 | Locale getLocale() 根据Accept-Language标头返回客户端将接受内容的首选区域设置。 |
8 | Object getAttribute(String name) 以Object形式返回指定属性的值,如果不存在给定名称的属性,则返回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) 以String形式返回指定请求标头的值。 |
15 | String getMethod() 返回用于发出此请求的HTTP方法的名称,例如,GET,POST或PUT。 |
16 | String getParameter(String name) 以String形式返回请求参数的值,如果参数不存在,则返回null。 |
17 | String getPathInfo() 返回与客户端发出此请求时发送的URL关联的任何额外路径信息 |
18 | String getProtocol() 返回请求的协议的名称和版本。 |
19 | String getQueryString() 返回路径后请求URL中包含的查询字符串。 |
20 | String getRemoteAddr() 返回发送请求的客户端的Internet协议(IP)地址。 |
21 | String getRemoteHost() 返回发送请求的客户端的完全限定名称。 |
22 | String getRemoteUser() 如果用户已通过身份验证,则返回发出此请求的用户的登录名;如果用户尚未通过身份验证,则返回null。 |
23 | String getRequestURI() 将此请求的URL部分从协议名称返回到HTTP请求第一行中的查询字符串。 |
24 | String getRequestedSessionId() 返回客户端指定的会话ID。 |
25 | String getServletPath() 返回此请求调用JSP的URL的一部分。 |
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标头请求示例
以下是使用HttpServletRequest的getHeaderNames()方法读取HTTP头信息的示例。 此方法返回一个Enumeration,其中包含与当前HTTP请求关联的标头信息。
一旦我们有了Enumeration,我们就可以以标准方式循环Enumeration,使用hasMoreElements()方法确定何时停止并使用nextElement()方法获取每个参数名称
// Import required java libraries
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
// Extend HttpServlet class
public class DisplayHeader extends HttpServlet {
// Method to handle GET method request.
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String title = "HTTP Header Request Example";
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n"+
"<body bgcolor = \"#f0f0f0\">\n" +
"<h1 align = \"center\">" + title + "</h1>\n" +
"<table width = \"100%\" border = \"1\" align = \"center\">\n" +
"<tr bgcolor = \"#949494\">\n" +
"<th>Header Name</th><th>Header Value(s)</th>\n"+
"</tr>\n"
);
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");
}
out.println("</table>\n</body></html>");
}
// Method to handle POST method request.
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
现在调用上面的servlet会产生以下结果 -
<h1 align="center">HTTP Header Request Example</h1>
标题名称 | 标题值 |
---|---|
accept | */* |
accept-language | en-us |
user-agent | Mozilla/4.0(兼容; 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 |
Servlets - Server HTTP Response
如前一章所述,当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编程中经常使用它们 -
Sr.No. | 标题和说明 |
---|---|
1 | Allow 此标头指定服务器支持的请求方法(GET,POST等)。 |
2 | Cache-Control 此标头指定可以安全地缓存响应文档的环境。 它可以具有public , private或no-cache等值。公共意味着文档是可缓存的,私有意味着文档是针对单个用户的,并且只能存储在私有(非共享)缓存中,nocache意味着永远不应该缓存文档。 |
3 | Connection 此标头指示浏览器是否在HTTP连接中使用持久性。 值close指示浏览器不使用持久HTTP连接, keepalive指示使用持久连接。 |
4 | Content-Disposition 此标头允许您请求浏览器要求用户将响应保存到给定名称的文件中。 |
5 | Content-Encoding 此标头指定在传输过程中页面的编码方式。 |
6 | Content-Language 此标头表示文档的编写语言。 例如en,en-us,ru等 |
7 | Content-Length 此标头指示响应中的字节数。 仅当浏览器使用持久(保持活动)HTTP连接时才需要此信息。 |
8 | Content-Type 此标头提供响应文档的MIME(多用途Internet邮件扩展)类型。 |
9 | Expires 此标头指定内容应被视为过期的时间,因此不再被缓存。 |
10 | Last-Modified 此标头指示文档上次更改的时间。 然后,客户端可以缓存文档,并在以后的请求中通过If-Modified-Since请求标头提供日期。 |
11 | Location 此标头应包含在状态代码为300s的所有响应中。 这会通知浏览器文档地址。 浏览器会自动重新连接到此位置并检索新文档。 |
12 | Refresh 此标头指定浏览器应该多久要求更新的页面。 您可以指定刷新页面的时间(以秒为单位)。 |
13 | Retry-After 此标头可与503(服务不可用)响应结合使用,以告知客户端可以多快重复其请求。 |
14 | Set-Cookie 此标头指定与页面关联的cookie。 |
设置HTTP响应标头的方法
有以下方法可用于在servlet程序中设置HTTP响应头。 这些方法可用于HttpServletResponse对象。
Sr.No. | 方法和描述 |
---|---|
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标头响应示例
您已经看到setContentType()方法在前面的示例中工作,下面的示例也将使用相同的方法,另外我们将使用setIntHeader()方法来设置Refresh标头。
// Import required java libraries
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
// Extend HttpServlet class
public class Refresh extends HttpServlet {
// Method to handle GET method request.
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Set refresh, autoload time as 5 seconds
response.setIntHeader("Refresh", 5);
// Set response content type
response.setContentType("text/html");
// 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;
PrintWriter out = response.getWriter();
String title = "Auto Refresh Header Setting";
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n"+
"<body bgcolor = \"#f0f0f0\">\n" +
"<h1 align = \"center\">" + title + "</h1>\n" +
"<p>Current Time is: " + CT + "</p>\n"
);
}
// Method to handle POST method request.
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
现在调用上面的servlet会在每5秒后显示当前系统时间,如下所示。 只需运行servlet并等待查看结果 -
<h1 align="center">Auto Refresh Header Setting</h1>
<p>Current Time is: 9:44:50 PM</p>
Servlets - Http Status Codes
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 | Continue | 服务器只收到请求的一部分,但只要它没有被拒绝,客户端就应该继续请求 |
101 | 切换协议 | 服务器切换协议。 |
200 | OK | 请求没问题 |
201 | Created | 请求已完成,并且已创建新资源 |
202 | Accepted | 请求被接受处理,但处理不完整。 |
203 | 非权威信息 | |
204 | 无内容 | |
205 | 重置内容 | |
206 | 部分内容 | |
300 | 多种选择 | 链接列表。 用户可以选择链接并转到该位置。 最多五个地址 |
301 | 永久移动 | 请求的页面已移至新网址 |
302 | Found | 请求的页面暂时移动到新的URL |
303 | 见其他 | 请求的页面可以在不同的URL下找到 |
304 | 没有修改 | |
305 | 使用代理服务器 | |
306 | Unused | 此代码用于以前的版本。 它已不再使用,但代码保留 |
307 | 临时重定向 | 请求的页面暂时移动到新的URL。 |
400 | 错误的请求 | 服务器不理解请求 |
401 | Unauthorized | 请求的页面需要用户名和密码 |
402 | 需要付款 | You cannot use this code yet |
403 | Forbidden | 禁止访问所请求的页面 |
404 | 未找到 | 服务器找不到请求的页面。 |
405 | 方法不允许 | 不允许在请求中指定的方法。 |
406 | 不能接受的 | 服务器只能生成客户端不接受的响应。 |
407 | 需要代理验证 | 在提供此请求之前,您必须使用代理服务器进行身份验证。 |
408 | 请求超时 | 请求花费的时间比服务器准备等待的时间长。 |
409 | Conflict | 由于冲突,请求无法完成。 |
410 | Gone | 请求的页面不再可用。 |
411 | 长度要求 | “内容长度”未定义。 没有它,服务器将不接受请求。 |
412 | 前提条件失败 | 请求中给出的前提条件由服务器评估为false。 |
413 | 请求的实体太大 | 服务器不接受请求,因为请求实体太大。 |
414 | 请求网址太长 | 服务器不接受请求,因为网址太长。 将“post”请求转换为带有长查询信息的“get”请求时发生。 |
415 | 不支持的媒体类型 | 服务器不接受请求,因为不支持媒体类型。 |
417 | 期望失败 | |
500 | 内部服务器错误 | 请求未完成。 服务器遇到意外情况。 |
501 | 未实现 | 请求未完成。 服务器不支持所需的功能。 |
502 | 错误的网关 | 请求未完成。 服务器从上游服务器收到无效响应。 |
503 | 暂停服务 | 请求未完成。 服务器暂时超载或关闭。 |
504 | 网关超时 | 网关已超时。 |
505 | 不支持HTTP版本 | 服务器不支持“http协议”版本。 |
设置HTTP状态代码的方法
可以使用以下方法在servlet程序中设置HTTP状态代码。 这些方法可用于HttpServletResponse对象。
Sr.No. | 方法和描述 |
---|---|
1 | public void setStatus ( int statusCode ) 此方法设置任意状态代码。 setStatus方法将int(状态代码)作为参数。 如果您的响应包含特殊状态代码和文档,请务必在使用PrintWriter实际返回任何内容之前调用setStatus。 |
2 | public void sendRedirect(String url) 此方法生成302响应以及提供新文档的URL的Location标头 |
3 | public void sendError(int code, String message) 此方法发送状态代码(通常为404)以及在HTML文档内自动格式化并发送到客户端的短消息。 |
HTTP状态代码示例
以下示例将向客户端浏览器发送407错误代码,浏览器将显示“需要身份验证!!!” 信息。
// Import required java libraries
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
// Extend HttpServlet class
public class showError extends HttpServlet {
// Method to handle GET method request.
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Set error code and reason.
response.sendError(407, "Need authentication!!!" );
}
// Method to handle POST method request.
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
现在调用上面的servlet会显示以下结果 -
<h1 style="font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;">HTTP Status 407 - Need authentication!!!</h1>
<p><b style="font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;" class="notranslate">type</b> Status report</p>
<p><b style="font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;" class="notranslate">message</b><u>Need authentication!!!</u></p>
<p><b style="font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;" class="notranslate">description</b><u>The client must first authenticate itself with the proxy (Need authentication!!!).</u></p>
<h3 style="font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;">Apache Tomcat/5.5.29</h3>
Servlets - Writing Filters
Servlet过滤器是可用于Servlet编程的Java类,用于以下目的 -
在客户端访问后端资源之前拦截客户端的请求。
在将服务器发送回客户端之前操纵服务器的响应。
规格建议有各种类型的过滤器 -
- 验证过滤器。
- 数据压缩过滤器。
- 加密过滤器。
- 触发资源访问事件的过滤器。
- 图像转换滤镜。
- 记录和审核过滤器。
- MIME-TYPE链过滤器。
- 标记过滤器。
- 转换XML内容的XSL/T过滤器。
过滤器部署在部署描述符文件web.xml ,然后映射到应用程序部署描述符中的servlet名称或URL模式。
当Web容器启动Web应用程序时,它会创建您在部署描述符中声明的每个过滤器的实例。 过滤器按照在部署描述符中声明的顺序执行。
Servlet过滤方法
过滤器只是一个实现javax.servlet.Filter接口的Java类。 javax.servlet.Filter接口定义了三个方法 -
Sr.No. | 方法和描述 |
---|---|
1 | public void doFilter (ServletRequest, ServletResponse, FilterChain) 每次由于客户端请求链末端的资源而请求/响应对通过链时,容器都会调用此方法。 |
2 | public void init(FilterConfig filterConfig) Web容器调用此方法以向过滤器指示它正在投入使用。 |
3 | public void destroy() Web容器调用此方法以向过滤器指示它正在停止服务。 |
Servlet过滤器 - 示例
以下是Servlet过滤器示例,它将打印客户端IP地址和当前日期时间。 这个例子可以让你对Servlet过滤器有基本的了解,但你可以使用相同的概念编写更复杂的过滤器应用程序 -
// 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并将您的类文件放在“Tomcat-installationdirectory”/ webapps/ROOT/WEB-INF/classes中
Web.xml中的Servlet过滤器映射
定义过滤器然后映射到URL或Servlet,其方式与定义Servlet的方式非常相似,然后映射到URL模式。 在部署描述符文件web.xml为filter标记创建以下条目
<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,因为我们在配置中指定了/* 。 如果要仅在几个servlet上应用过滤器,则可以指定特定的servlet路径。
现在尝试以通常的方式调用任何servlet,您将在Web服务器日志中看到生成的日志。 您可以使用Log4J记录器将上面的日志记录在单独的文件中。
使用多个过滤器
您的Web应用程序可能会定义具有特定用途的多个不同过滤器 考虑一下,您定义了两个过滤器AuthenFilter和LogFilter 。 其余的过程将保持如上所述,除非您需要创建如下所述的不同映射 -
<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中filter-mapping元素的顺序决定了Web容器将过滤器应用于servlet的顺序。 要反转过滤器的顺序,您只需要反转web.xml文件中的过滤器映射元素。
例如,上面的示例首先应用LogFilter,然后将AuthenFilter应用于任何servlet,但以下示例将颠倒顺序 -
<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>
Servlets - Exception Handling
当servlet抛出异常时,Web容器将在web.xml中搜索使用exception-type元素的配置,以便与抛出的异常类型匹配。
您必须使用web.xml中的error-page元素来指定servlet的调用以响应某些exceptions或HTTP status codes 。
web.xml Configuration
考虑一下,你有一个ErrorHandler servlet,只要有任何定义的异常或错误就会调用它。 以下是在web.xml中创建的条目。
<!-- servlet definition -->
<servlet>
<servlet-name>ErrorHandler</servlet-name>
<servlet-class>ErrorHandler</servlet-class>
</servlet>
<!-- servlet mappings -->
<servlet-mapping>
<servlet-name>ErrorHandler</servlet-name>
<url-pattern>/ErrorHandler</url-pattern>
</servlet-mapping>
<!-- error-code related error pages -->
<error-page>
<error-code>404</error-code>
<location>/ErrorHandler</location>
</error-page>
<error-page>
<error-code>403</error-code>
<location>/ErrorHandler</location>
</error-page>
<!-- exception-type related error pages -->
<error-page>
<exception-type>
javax.servlet.ServletException
</exception-type >
<location>/ErrorHandler</location>
</error-page>
<error-page>
<exception-type>java.io.IOException</exception-type >
<location>/ErrorHandler</location>
</error-page>
如果你想为所有异常都有一个通用的错误处理程序,那么你应该定义以下错误页面,而不是为每个异常定义单独的错误页面元素 -
<error-page>
<exception-type>java.lang.Throwable</exception-type >
<location>/ErrorHandler</location>
</error-page>
以下是有关异常处理的上述web.xml的注意事项 -
servlet ErrorHandler以通常的方式定义为任何其他servlet并在web.xml中配置。
如果状态代码为404(未找到)或403(禁止)时出现任何错误,则将调用ErrorHandler servlet。
如果Web应用程序抛出ServletException或IOException,则Web容器将调用/ ErrorHandler servlet。
您可以定义不同的错误处理程序来处理不同类型的错误或异常。 以上示例非常通用,希望它能够解释您的基本概念。
请求属性 - 错误/异常
以下是错误处理servlet可以访问的请求属性列表,以分析错误/异常的性质。
Sr.No. | 属性和描述 |
---|---|
1 | javax.servlet.error.status_code 此属性提供状态代码,可以在存储为java.lang.Integer数据类型后进行存储和分析。 |
2 | javax.servlet.error.exception_type 此属性提供有关异常类型的信息,该异常类型可以在存储为java.lang.Class数据类型后进行存储和分析。 |
3 | javax.servlet.error.message 此属性提供信息确切的错误消息,可以在存储到java.lang.String数据类型后进行存储和分析。 |
4 | javax.servlet.error.request_uri 此属性提供有关调用servlet的URL的信息,并且可以在存储为java.lang.String数据类型后进行存储和分析。 |
5 | javax.servlet.error.exception 此属性提供有关引发的异常的信息,可以存储和分析。 |
6 | javax.servlet.error.servlet_name 此属性提供servlet名称,该名称可以在存储为java.lang.String数据类型后进行存储和分析。 |
错误处理程序Servlet示例
这个例子将让您基本了解Servlet中的异常处理,但您可以使用相同的概念编写更复杂的过滤器应用程序 -
这个例子将让您基本了解Servlet中的异常处理,但您可以使用相同的概念编写更复杂的过滤器应用程序:
// Import required java libraries
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
// Extend HttpServlet class
public class ErrorHandler extends HttpServlet {
// Method to handle GET method request.
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Analyze the servlet exception
Throwable throwable = (Throwable)
request.getAttribute("javax.servlet.error.exception");
Integer statusCode = (Integer)
request.getAttribute("javax.servlet.error.status_code");
String servletName = (String)
request.getAttribute("javax.servlet.error.servlet_name");
if (servletName == null) {
servletName = "Unknown";
}
String requestUri = (String)
request.getAttribute("javax.servlet.error.request_uri");
if (requestUri == null) {
requestUri = "Unknown";
}
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String title = "Error/Exception Information";
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " +
"transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor = \"#f0f0f0\">\n");
if (throwable == null && statusCode == null) {
out.println("<h2>Error information is missing</h2>");
out.println("Please return to the <a href=\"" +
response.encodeURL("http://localhost:8080/") +
"\">Home Page</a>.");
} else if (statusCode != null) {
out.println("The status code : " + statusCode);
} else {
out.println("<h2>Error information</h2>");
out.println("Servlet Name : " + servletName + "</br></br>");
out.println("Exception Type : " + throwable.getClass( ).getName( ) + "</br></br>");
out.println("The request URI: " + requestUri + "<br><br>");
out.println("The exception message: " + throwable.getMessage( ));
}
out.println("</body>");
out.println("</html>");
}
// Method to handle POST method request.
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
以通常的方式编译ErrorHandler.java并将您的类文件放入
让我们在web.xml中添加以下配置来处理异常 -
<servlet>
<servlet-name>ErrorHandler</servlet-name>
<servlet-class>ErrorHandler</servlet-class>
</servlet>
<!-- servlet mappings -->
<servlet-mapping>
<servlet-name>ErrorHandler</servlet-name>
<url-pattern>/ErrorHandler</url-pattern>
</servlet-mapping>
<error-page>
<error-code>404</error-code>
<location>/ErrorHandler</location>
</error-page>
<error-page>
<exception-type>java.lang.Throwable</exception-type >
<location>/ErrorHandler</location>
</error-page>
现在尝试使用引发任何异常或键入错误URL的servlet,这将触发Web容器调用ErrorHandler servlet并按编程显示相应的消息。 例如,如果您键入错误的网址,则会显示以下结果 -
The status code : 404
上述代码可能无法用于某些Web浏览器。 所以尝试Mozilla和Safari,它应该工作。
Servlets - Cookies Handling
Cookie是存储在客户端计算机上的文本文件,用于各种信息跟踪目的。 Java Servlets透明地支持HTTP cookie。
确定回归用户涉及三个步骤 -
服务器脚本将一组cookie发送到浏览器。 例如姓名,年龄或身份证号码等。
浏览器将此信息存储在本地计算机上以供将来使用
当下次浏览器向Web服务器发送任何请求时,它会将这些cookie信息发送到服务器,服务器使用该信息来识别用户。
本章将教您如何设置或重置cookie,如何访问它们以及如何删除它们。
Cookie的剖析
Cookie通常设置在HTTP标头中(尽管JavaScript也可以直接在浏览器上设置cookie)。 设置cookie的servlet可能会发送看起来像这样的标题 -
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 = iowiki.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
然后,servlet将通过请求方法request.getCookies()访问cookie,该请求方法返回Cookie对象的数组。
Servlet Cookie方法
以下是在servlet中操作cookie时可以使用的有用方法列表。
Sr.No. | 方法和描述 |
---|---|
1 | public void setDomain(String pattern) 此方法设置cookie适用的域,例如iowiki.com。 |
2 | public String getDomain() 此方法获取cookie适用的域,例如iowiki.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应用的路径。 如果未指定路径,则会为与当前页面相同的目录中的所有URL以及所有子目录返回cookie。 |
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。 |
使用Servlet设置Cookie
使用servlet设置cookie涉及三个步骤 -
(1) Creating a Cookie object - 使用cookie名称和cookie值调用Cookie构造函数,两者都是字符串。
Cookie cookie = new Cookie("key","value");
请记住,名称和值都不应包含空格或以下任何字符 -
[ ] ( ) = , "/? @ : ;
(2) Setting the maximum age - 使用setMaxAge指定cookie应该有效的时间长度(以秒为单位)。 以下将设置一个24小时的cookie。
cookie.setMaxAge(60 * 60 * 24);
(3) Sending the Cookie into the HTTP response headers - 您使用response.addCookie在HTTP响应头中添加cookie,如下所示 -
response.addCookie(cookie);
例子 (Example)
我们修改表单示例以设置名字和姓名的cookie。
// Import required java libraries
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
// Extend HttpServlet class
public class HelloForm extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 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 );
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String title = "Setting Cookies Example";
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head>
<title>" + title + "</title>
</head>\n" +
"<body bgcolor = \"#f0f0f0\">\n" +
"<h1 align = \"center\">" + title + "</h1>\n" +
"<ul>\n" +
" <li><b>First Name</b>: "
+ request.getParameter("first_name") + "\n" +
" <li><b>Last Name</b>: "
+ request.getParameter("last_name") + "\n" +
"</ul>\n" +
"</body>
</html>"
);
}
}
编译上面的servlet HelloForm并在web.xml文件中创建适当的条目,最后尝试按照HTML页面调用servlet。
<html>
<body>
<form action = "HelloForm" 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中,并将其放在
尝试输入名字和姓氏,然后单击“提交”按钮。 这将在屏幕上显示名字和姓氏,同时它将设置两个cookie firstName和lastName,当您下次按Submit按钮时,它将被传递回服务器。
下一节将向您解释如何在Web应用程序中访问这些cookie。
用Servlet读取Cookies
要读取cookie,需要通过调用HttpServletRequest的getCookies()方法来创建javax.servlet.http.Cookie对象的数组。 然后遍历数组,并使用getName()和getValue()方法访问每个cookie和相关值。
例子 (Example)
让我们读一下我们在前面的例子中设置的cookie -
// Import required java libraries
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
// Extend HttpServlet class
public class ReadCookies extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Cookie cookie = null;
Cookie[] cookies = null;
// Get an array of Cookies associated with this domain
cookies = request.getCookies();
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String title = "Reading Cookies Example";
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " +
"transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor = \"#f0f0f0\">\n" );
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>");
}
out.println("</body>");
out.println("</html>");
}
}
编译上面的servlet ReadCookies并在web.xml文件中创建适当的条目。 如果您将first_name cookie设置为“John”并将last_name cookie设置为“Player”,则运行http://localhost:8080/ReadCookies将显示以下结果 -
<h2> Found Cookies Name and Value</h2>
Name : first_name, Value: John
Name : last_name, Value: Player
使用Servlet删除Cookies
删除cookie非常简单。 如果您想删除cookie,那么您只需要按照以下三个步骤进行操作 -
读取已存在的cookie并将其存储在Cookie对象中。
使用setMaxAge()方法将cookie年龄设置为零以删除现有cookie
将此cookie添加回响应头。
例子 (Example)
以下示例将删除名为“first_name”的现有cookie,并在下次运行ReadCookies servlet时为first_name返回null值。
// Import required java libraries
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
// Extend HttpServlet class
public class DeleteCookies extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Cookie cookie = null;
Cookie[] cookies = null;
// Get an array of Cookies associated with this domain
cookies = request.getCookies();
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String title = "Delete Cookies Example";
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor = \"#f0f0f0\">\n" );
if( cookies != null ) {
out.println("<h2> 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>");
}
out.println("</body>");
out.println("</html>");
}
}
编译上面的servlet DeleteCookies并在web.xml文件中创建适当的条目。 现在运行http://localhost:8080/DeleteCookies将显示以下结果 -
<h2>Cookies Name and Value</h2>
<p>Deleted cookie : first_name</p>
<p>Name : first_name, Value: John</p>
<p>Name : last_name, Value: Player</p>
现在尝试运行http://localhost:8080/ReadCookies ,它将只显示一个cookie,如下所示 -
<h2> Found Cookies Name and Value</h2>
Name : last_name, Value: Player
您可以手动删除Internet Explorer中的cookie。 从“工具”菜单开始,然后选择“Internet选项”。 要删除所有cookie,请按Delete Cookies。
Servlets - Session Tracking
HTTP是一种“无状态”协议,这意味着每次客户端检索网页时,客户端都会打开与Web服务器的单独连接,服务器自动不会保留以前客户端请求的任何记录。
仍然有以下三种方法来维护Web客户端和Web服务器之间的会话 -
Cookies
Web服务器可以将唯一的会话ID作为cookie分配给每个Web客户端,并且对于来自客户端的后续请求,可以使用收到的cookie来识别它们。
这可能不是一种有效的方法,因为很多时候浏览器不支持cookie,因此我不建议使用此过程来维护会话。
隐藏的表单字段
Web服务器可以发送隐藏的HTML表单字段以及唯一的会话ID,如下所示 -
<input type = "hidden" name = "sessionid" value = "12345">
此条目表示在提交表单时,指定的名称和值将自动包含在GET或POST数据中。 每次Web浏览器发回请求时,session_id值都可用于保持不同Web浏览器的跟踪。
这可能是跟踪会话的有效方式,但单击常规()超文本链接不会导致表单提交,因此隐藏的表单字段也不能支持常规会话跟踪。
URL重写
您可以在标识会话的每个URL的末尾附加一些额外数据,并且服务器可以将该会话标识符与其存储的有关该会话的数据相关联。
例如,使用http://iowiki.com/file.htm;sessionid = 12345,会话标识符作为sessionid = 12345附加,可以在Web服务器上访问该标识符以标识客户端。
URL重写是维护会话的更好方法,即使浏览器不支持cookie也能正常工作。 URL重写的缺点是,您必须动态生成每个URL以分配会话ID,即使是简单的静态HTML页面也是如此。
HttpSession对象
除了上面提到的三种方式之外,servlet还提供了HttpSession接口,它提供了一种在多个页面请求中识别用户或访问网站并存储有关该用户的信息的方法。
servlet容器使用此接口在HTTP客户端和HTTP服务器之间创建会话。 会话在指定的时间段内持续存在,来自用户的多个连接或页面请求。
您将通过调用HttpServletRequest的公共方法getSession()来获取HttpSession对象,如下所示 -
HttpSession session = request.getSession();
在将任何文档内容发送到客户端之前,需要调用request.getSession() 。 以下是HttpSession对象可用的重要方法的摘要 -
Sr.No. | 方法和描述 |
---|---|
1 | public Object getAttribute(String name) 此方法返回在此会话中使用指定名称绑定的对象,如果名称下没有绑定任何对象,则返回null。 |
2 | public Enumeration getAttributeNames() 此方法返回Enumeration of String对象,其中包含绑定到此会话的所有对象的名称。 |
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对象查找会话的创建时间和上次访问时间。 如果一个新会话尚不存在,我们会将该会话与该请求相关联。
// Import required java libraries
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
// Extend HttpServlet class
public class SessionTrack extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Create a session object if it is already not created.
HttpSession session = request.getSession(true);
// Get session creation time.
Date createTime = new Date(session.getCreationTime());
// Get last access time of this web page.
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 web page.
if (session.isNew()) {
title = "Welcome to my website";
session.setAttribute(userIDKey, userID);
} else {
visitCount = (Integer)session.getAttribute(visitCountKey);
visitCount = visitCount + 1;
userID = (String)session.getAttribute(userIDKey);
}
session.setAttribute(visitCountKey, visitCount);
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " +
"transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor = \"#f0f0f0\">\n" +
"<h1 align = \"center\">" + title + "</h1>\n" +
"<h2 align = \"center\">Session Infomation</h2>\n" +
"<table border = \"1\" align = \"center\">\n" +
"<tr bgcolor = \"#949494\">\n" +
" <th>Session info</th><th>value</th>
</tr>\n" +
"<tr>\n" +
" <td>id</td>\n" +
" <td>" + session.getId() + "</td>
</tr>\n" +
"<tr>\n" +
" <td>Creation Time</td>\n" +
" <td>" + createTime + " </td>
</tr>\n" +
"<tr>\n" +
" <td>Time of Last Access</td>\n" +
" <td>" + lastAccessTime + " </td>
</tr>\n" +
"<tr>\n" +
" <td>User ID</td>\n" +
" <td>" + userID + " </td>
</tr>\n" +
"<tr>\n" +
" <td>Number of visits</td>\n" +
" <td>" + visitCount + "</td>
</tr>\n" +
"</table>\n" +
"</body>
</html>"
);
}
}
编译上面的servlet SessionTrack并在web.xml文件中创建适当的条目。 现在运行http://localhost:8080/SessionTrack会在第一次运行时显示以下结果 -
<h1 align="center">Welcome to my website</h1>
<h2 align="center">Session Infomation</h2>
会话信息 | 值 |
---|---|
id | 0AE3EC93FF44E3C525B4351B77ABB2D5 |
创作时间 | Tue Jun 08 17:26:40 GMT + 04:00 2010 |
最后访问时间 | Tue Jun 08 17:26:40 GMT + 04:00 2010 |
用户身份 | ABCD |
访问次数 | 0 |
现在尝试第二次运行相同的servlet,它将显示以下结果。
<h1 align="center">Welcome Back to my website</h1>
<h2 align="center">Session Infomation</h2>
信息类型 | 值 |
---|---|
id | 0AE3EC93FF44E3C525B4351B77ABB2D5 |
创作时间 | Tue Jun 08 17:26:40 GMT + 04:00 2010 |
最后访问时间 | Tue Jun 08 17:26:40 GMT + 04:00 2010 |
用户身份 | ABCD |
访问次数 | 1 |
删除会话数据
完成用户的会话数据后,您有多种选择 -
Remove a particular attribute - 您可以调用public void removeAttribute(String name)方法来删除与特定键关联的值。
Delete the whole session - 您可以调用public void invalidate()方法来丢弃整个会话。
Setting Session timeout - 您可以调用public void setMaxInactiveInterval(int interval)方法来单独设置会话的超时。
Log the user out - 支持servlet 2.4的服务器,您可以调用logout将客户端记录到Web服务器之外,并使属于所有用户的所有会话无效。
web.xml Configuration - 如果您使用的是Tomcat,除了上述方法之外,您还可以在web.xml文件中配置会话超时,如下所示。
<session-config>
<session-timeout>15</session-timeout>
</session-config>
超时以分钟表示,并覆盖Tomcat中的默认超时30分钟。
servlet中的getMaxInactiveInterval()方法以秒为单位返回该会话的超时时间。 因此,如果您的会话在web.xml中配置了15分钟,则getMaxInactiveInterval()将返回900。
Servlets - Database Access
本教程假设您已了解JDBC应用程序的工作原理。 在通过servlet开始数据库访问之前,请确保您具有正确的JDBC环境设置以及数据库。
有关如何使用JDBC及其环境设置访问数据库的更多详细信息,您可以浏览我们的JDBC教程 。
从基本概念开始,让我们创建一个简单的表,并在该表中创建几条记录,如下所示 -
Create Table
要在TEST数据库中创建Employees表,请使用以下步骤 -
Step 1
打开Command Prompt并切换到安装目录,如下所示 -
C:\>
C:\>cd Program Files\MySQL\bin
C:\Program Files\MySQL\bin>
Step 2
登录数据库如下
C:\Program Files\MySQL\bin>mysql -u root -p
Enter password: ********
mysql>
Step 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>
创建数据记录 (Create Data Records)
最后,您在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>
访问数据库
这是一个示例,显示如何使用Servlet访问TEST数据库。
// Loading required libraries
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;
public class DatabaseAccess extends HttpServlet{
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// JDBC driver name and database URL
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static final String DB_URL="jdbc:mysql://localhost/TEST";
// Database credentials
static final String USER = "root";
static final String PASS = "password";
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String title = "Database Result";
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor = \"#f0f0f0\">\n" +
"<h1 align = \"center\">" + title + "</h1>\n");
try {
// Register JDBC driver
Class.forName("com.mysql.jdbc.Driver");
// Open a connection
Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
// Execute SQL query
Statement stmt = conn.createStatement();
String sql;
sql = "SELECT id, first, last, age FROM Employees";
ResultSet rs = stmt.executeQuery(sql);
// Extract data from result set
while(rs.next()){
//Retrieve by column name
int id = rs.getInt("id");
int age = rs.getInt("age");
String first = rs.getString("first");
String last = rs.getString("last");
//Display values
out.println("ID: " + id + "<br>");
out.println(", Age: " + age + "<br>");
out.println(", First: " + first + "<br>");
out.println(", Last: " + last + "<br>");
}
out.println("</body></html>");
// Clean-up environment
rs.close();
stmt.close();
conn.close();
} catch(SQLException se) {
//Handle errors for JDBC
se.printStackTrace();
} catch(Exception e) {
//Handle errors for Class.forName
e.printStackTrace();
} finally {
//finally block used to close resources
try {
if(stmt!=null)
stmt.close();
} catch(SQLException se2) {
} // nothing we can do
try {
if(conn!=null)
conn.close();
} catch(SQLException se) {
se.printStackTrace();
} //end finally try
} //end try
}
}
现在让我们编译上面的servlet并在web.xml中创建以下条目
....
<servlet>
<servlet-name>DatabaseAccess</servlet-name>
<servlet-class>DatabaseAccess</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DatabaseAccess</servlet-name>
<url-pattern>/DatabaseAccess</url-pattern>
</servlet-mapping>
....
现在使用URL http:// localhost:8080/DatabaseAccess调用此servlet,它将显示以下响应 -
<h1 align="center">Database Result</h1>
ID: 100, Age: 18, First: Zara, Last: Ali
ID: 101, Age: 25, First: Mahnaz, Last: Fatma
ID: 102, Age: 30, First: Zaid, Last: Khan
ID: 103, Age: 28, First: Sumit, Last: Mittal
Servlets - File Uploading
Servlet可与HTML表单标记一起使用,以允许用户将文件上载到服务器。 上传的文件可以是文本文件或图像文件或任何文档。
创建文件上载表单
以下HTM代码创建了一个上传器表单。 以下是需要注意的重点 -
表单method属性应设置为POST方法,并且不能使用GET方法
表单enctype属性应设置为multipart/form-data 。
表单action属性应设置为servlet文件,该文件将处理后端服务器上的文件上载。 以下示例使用UploadServlet servlet上传文件。
要上传单个文件,您应该使用带有属性type =“file”的单个标记。 要允许多个文件上载,请包含多个具有不同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选择文件,当用户点击“上传文件”时,表格将与选定的文件一起提交 -
<b class="notranslate">File Upload:</b>
Select a file to upload:
<input type="file" name="file" size="50">
<input type="button" value="Upload File">
NOTE: This is just dummy form and would not work.
编写后端Servlet
以下是servlet UploadServlet ,它负责接受上传的文件并将其存储在“Tomcat-installation-directory”/ webapps/data目录中。 此目录名也可以使用外部配置添加,例如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>
以下是UploadServlet的源代码,它可以一次处理多个文件上传。 在继续之前,您必须确保以下事项 -
以下示例依赖于FileUpload,因此请确保您的类路径中包含最新版本的commons-fileupload.xxjar文件。 您可以从https://commons.apache.org/fileupload/下载它。
FileUpload依赖于Commons IO,因此请确保您的类路径中包含最新版本的commons-io-xxjar文件。 您可以从https://commons.apache.org/io/下载。
在测试以下示例时,您应该上传大小小于maxFileSize的文件,否则将无法上载文件。
确保您提前创建了目录c:\temp和c:\apache-tomcat8.0.28\webapps\data。
// Import required java libraries
import java.io.*;
import java.util.*;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.output.*;
public class UploadServlet extends HttpServlet {
private boolean isMultipart;
private String filePath;
private int maxFileSize = 50 * 1024;
private int maxMemSize = 4 * 1024;
private File file ;
public void init( ){
// Get the file location where it would be stored.
filePath = getServletContext().getInitParameter("file-upload");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, java.io.IOException {
// Check that we have a file upload request
isMultipart = ServletFileUpload.isMultipartContent(request);
response.setContentType("text/html");
java.io.PrintWriter out = response.getWriter( );
if( !isMultipart ) {
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>");
return;
}
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>Servlet 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();
String contentType = fi.getContentType();
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: " + fileName + "<br>");
}
}
out.println("</body>");
out.println("</html>");
} catch(Exception ex) {
System.out.println(ex);
}
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, java.io.IOException {
throw new ServletException("GET method used with " +
getClass( ).getName( )+": POST method required.");
}
}
}
编译和运行Servlet
编译上面的servlet UploadServlet并在web.xml文件中创建所需的条目,如下所示。
<servlet>
<servlet-name>UploadServlet</servlet-name>
<servlet-class>UploadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UploadServlet</servlet-name>
<url-pattern>/UploadServlet</url-pattern>
</servlet-mapping>
现在尝试使用您在上面创建的HTML表单上传文件。 当您尝试http:// localhost:8080/UploadFile.htm时,它将显示以下结果,这将有助于您从本地计算机上载任何文件。
<b class="notranslate">File Upload:</b>
<p>Select a file to upload:</p>
<input type="file" name="file" size="50">
<input type="button" value="Upload File">
如果您的servlet脚本正常工作,您的文件应该上传到c:\apache-tomcat8.0.28\webapps\data \目录。
Servlets - Handling Date
使用Servlet最重要的优点之一是您可以使用核心Java中可用的大多数方法。 本教程将引导您完成Java提供的Date类,该类可在java.util包中找到,该类封装了当前的日期和时间。
Date类支持两个构造函数。 第一个构造函数使用当前日期和时间初始化对象。
Date( )
以下构造函数接受一个参数,该参数等于自1970年1月1日午夜以来经过的毫秒数
Date(long millisec)
一旦有了Date对象,就可以调用以下任何支持方法来使用日期 -
Sr.No. | 方法和描述 |
---|---|
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) 将调用对象的值与date的值进行比较。 如果值相等则返回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) 设置时间指定的时间和日期,表示从1970年1月1日午夜开始的经过时间(以毫秒为单位)。 |
10 | String toString( ) 将调用Date对象转换为字符串并返回结果。 |
获取当前日期和时间
这很容易在Java Servlet中获取当前日期和时间。 您可以使用带有toString()方法的简单Date对象来打印当前日期和时间,如下所示 -
// Import required java libraries
import java.io.*;
import java.util.Date;
import javax.servlet.*;
import javax.servlet.http.*;
// Extend HttpServlet class
public class CurrentDate extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String title = "Display Current Date & Time";
Date date = new Date();
String docType = "<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor = \"#f0f0f0\">\n" +
"<h1 align = \"center\">" + title + "</h1>\n" +
"<h2 align = \"center\">" + date.toString() + "</h2>\n" +
"</body>
</html>"
);
}
}
现在让我们编译上面的servlet并在web.xml中创建适当的条目,然后使用URL http:// localhost:8080/CurrentDate调用这个servlet。 这将产生以下结果 -
<h1 align="center">Display Current Date & Time</h1>
<h2 align="center">Mon Jun 21 21:46:49 GMT+04:00 2010</h2>
尝试刷新URL http:// localhost:8080/CurrentDate,每次刷新时都会发现秒数差异。
日期比较
如上所述,您可以使用Servlet中所有可用的Java方法。 如果您需要比较两个日期,以下是方法 -
您可以使用getTime()来获取两个对象自1970年1月1日午夜以来经过的毫秒数,然后比较这两个值。
您可以使用before(),after()和equals()之前的方法。 例如,因为该月的第12个月在18日之前,新日期(99,2,12)。之前(新日期(99,2,18))返回true。
您可以使用compareTo()方法,该方法由Comparable接口定义并由Date实现。
使用SimpleDateFormat格式化日期
SimpleDateFormat是一个具体的类,用于以区域设置敏感的方式格式化和解析日期。 SimpleDateFormat允许您从为日期时间格式选择任何用户定义的模式开始。
让我们修改上面的例子如下 -
// Import required java libraries
import java.io.*;
import java.text.*;
import java.util.Date;
import javax.servlet.*;
import javax.servlet.http.*;
// Extend HttpServlet class
public class CurrentDate extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String title = "Display Current Date & Time";
Date dNow = new Date( );
SimpleDateFormat ft = new SimpleDateFormat ("E yyyy.MM.dd 'at' hh:mm:ss a zzz");
String docType = "<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor = \"#f0f0f0\">\n" +
"<h1 align = \"center\">" + title + "</h1>\n" +
"<h2 align = \"center\">" + ft.format(dNow) + "</h2>\n" +
"</body>
</html>"
);
}
}
再次编译上面的servlet,然后使用URL http:// localhost:8080/CurrentDate调用此servlet。 这将产生以下结果 -
<h1 align="center">Display Current Date & Time</h1>
<h2 align="center">Mon 2010.06.21 at 10:06:44 PM GMT+04:00</h2>
简单的DateFormat格式代码
要指定时间格式,请使用时间模式字符串。 在此模式中,所有ASCII字母都保留为模式字母,其定义如下 -
字符 | 描述 | 例 |
---|---|---|
G | 时代指示符 | AD |
y | 四位数的年份 | 2001 |
M | 一年一个月 | 七月或七月 |
d | 一个月的日子 | 10 |
h | 上午/下午(1~12)小时 | 12 |
H | 一天中的小时(0~23) | 22 |
m | 一小时一分钟 | 30 |
s | 第二分钟 | 55 |
S | Millisecond | 234 |
E | 一周中的一天 | Tuesday |
D | 一年中的一天 | 360 |
F | 一个月中的某一天 | 2(7月第二个周三) |
w | 一周一周 | 40 |
W | 一周一个月 | 1 |
a | AM/PM标记 | PM |
k | 一天中的小时(1~24) | 24 |
K | 上午/下午(0~11)小时 | 10 |
z | 时区 | 东部标准时间 |
' | 逃避文字 | Delimiter |
" | 单引号 | ` |
有关操作日期的常量可用方法的完整列表,可以参考标准Java文档。
Servlets - Page Redirection
页面重定向是一种将客户端发送到请求之外的新位置的技术。 页面重定向通常在文档移动到新位置时使用,或者可能是由于负载平衡。
将请求重定向到另一个页面的最简单方法是使用响应对象的sendRedirect()方法。 以下是此方法的签名 -
public void HttpServletResponse.sendRedirect(String location)
throws IOException
此方法将响应以及状态代码和新页面位置发送回浏览器。 您也可以一起使用setStatus()和setHeader()方法来实现相同的效果 -
....
String site = "http://www.newpage.com" ;
response.setStatus(response.SC_MOVED_TEMPORARILY);
response.setHeader("Location", site);
....
例子 (Example)
此示例显示了servlet如何执行页面重定向到另一个位置 -
import java.io.*;
import java.sql.Date;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class PageRedirect extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Set response content type
response.setContentType("text/html");
// New location to be redirected
String site = new String("http://www.photofuntoos.com");
response.setStatus(response.SC_MOVED_TEMPORARILY);
response.setHeader("Location", site);
}
}
现在让我们编译上面的servlet并在web.xml中创建以下条目
....
<servlet>
<servlet-name>PageRedirect</servlet-name>
<servlet-class>PageRedirect</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PageRedirect</servlet-name>
<url-pattern>/PageRedirect</url-pattern>
</servlet-mapping>
....
现在使用URL http:// localhost:8080/PageRedirect调用此servlet。 这会将您重定向到URL http://www.photofuntoos.com。
Servlets - Hits Counter
网页命中计数器
很多时候,您会对了解网站特定页面的总点击次数感兴趣。 使用servlet计算这些命中非常简单,因为servlet的生命周期由运行它的容器控制。
以下是实现基于Servlet生命周期的简单页面计数器的步骤 -
在init()方法中初始化一个全局变量。
每次调用doGet()或doPost()方法时增加全局变量。
如果需要,可以使用数据库表在destroy()方法中存储全局变量的值。 下次初始化servlet时,可以在init()方法中读取该值。 此步骤是可选的。
如果您只想计算会话中的唯一页面匹配,那么您可以使用isNew()方法检查是否已在该会话中使用相同的页面。 此步骤是可选的。
您可以显示全局计数器的值,以显示您网站上的总点击次数。 此步骤也是可选的。
在这里,我假设不会重新启动Web容器。 如果重新启动或servlet被破坏,命中计数器将被重置。
例子 (Example)
这个例子展示了如何实现一个简单的页面点击计数器 -
import java.io.*;
import java.sql.Date;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class PageHitCounter extends HttpServlet {
private int hitCount;
public void init() {
// Reset hit counter.
hitCount = 0;
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Set response content type
response.setContentType("text/html");
// This method executes whenever the servlet is hit
// increment hitCount
hitCount++;
PrintWriter out = response.getWriter();
String title = "Total Number of Hits";
String docType = "<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor = \"#f0f0f0\">\n" +
"<h1 align = \"center\">" + title + "</h1>\n" +
"<h2 align = \"center\">" + hitCount + "</h2>\n" +
"</body>
</html>"
);
}
public void destroy() {
// This is optional step but if you like you
// can write hitCount value in your database.
}
}
现在让我们编译上面的servlet并在web.xml中创建以下条目
<servlet>
<servlet-name>PageHitCounter</servlet-name>
<servlet-class>PageHitCounter</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PageHitCounter</servlet-name>
<url-pattern>/PageHitCounter</url-pattern>
</servlet-mapping>
....
现在使用URL http:// localhost:8080/PageHitCounter调用此servlet。 每次刷新此页面时,这将增加一个,并显示以下结果 -
<h1 align="center">Total Number of Hits</h1>
<h2 align="center">6</h2>
<p style="text-align:center">Hit Counter for a Website:</p>
很多时候,您会对了解整个网站的总点击次数感兴趣。 这在Servlet中也很简单,我们可以使用过滤器实现这一点。
以下是实施基于过滤器生命周期的简单网站点击计数器的步骤 -
在过滤器的init()方法中初始化一个全局变量。
每次调用doFilter方法时增加全局变量。
如果需要,您可以使用数据库表在过滤器的destroy()方法中存储全局变量的值。 下次初始化过滤器时,可以在init()方法中读取该值。 此步骤是可选的。
在这里,我假设不会重新启动Web容器。 如果重新启动或servlet被破坏,命中计数器将被重置。
例子 (Example)
这个例子展示了如何实现一个简单的网站点击计数器 -
// Import required java libraries
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
public class SiteHitCounter implements Filter {
private int hitCount;
public void init(FilterConfig config) throws ServletException {
// Reset hit counter.
hitCount = 0;
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws java.io.IOException, ServletException {
// increase counter by one
hitCount++;
// Print the counter.
System.out.println("Site visits count :"+ hitCount );
// Pass request back down the filter chain
chain.doFilter(request,response);
}
public void destroy() {
// This is optional step but if you like you
// can write hitCount value in your database.
}
}
现在让我们编译上面的servlet并在web.xml中创建以下条目
....
<filter>
<filter-name>SiteHitCounter</filter-name>
<filter-class>SiteHitCounter</filter-class>
</filter>
<filter-mapping>
<filter-name>SiteHitCounter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
....
现在调用URL http:// localhost:8080 /之类的任何URL。 每当任何页面被点击时,这将增加一个计数器,并且它将在日志中显示以下消息 -
Site visits count : 1
Site visits count : 2
Site visits count : 3
Site visits count : 4
Site visits count : 5
..................
Servlets - Auto Page Refresh
考虑一个显示实时游戏得分或股票市场状态或货币兑换率的网页。 对于所有此类类型的页面,您需要使用浏览器的刷新或重新加载按钮定期刷新网页。
Java Servlet为您提供了一种机制,您可以通过这种机制创建一个网页,使其在给定的时间间隔后自动刷新。
刷新网页的最简单方法是使用响应对象的方法setIntHeader() 。 以下是此方法的签名 -
public void setIntHeader(String header, int headerValue)
此方法将标题“Refresh”发送回浏览器以及一个整数值,该值表示以秒为单位的时间间隔。
自动页面刷新示例
此示例显示了servlet如何使用setIntHeader()方法执行自动页面刷新以设置Refresh标头。
// Import required java libraries
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
// Extend HttpServlet class
public class Refresh extends HttpServlet {
// Method to handle GET method request.
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Set refresh, autoload time as 5 seconds
response.setIntHeader("Refresh", 5);
// Set response content type
response.setContentType("text/html");
// 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;
PrintWriter out = response.getWriter();
String title = "Auto Page Refresh using Servlet";
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n"+
"<body bgcolor = \"#f0f0f0\">\n" +
"<h1 align = \"center\">" + title + "</h1>\n" +
"<p>Current Time is: " + CT + "</p>\n"
);
}
// Method to handle POST method request.
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
现在让我们编译上面的servlet并在web.xml中创建以下条目
....
<servlet>
<servlet-name>Refresh</servlet-name>
<servlet-class>Refresh</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Refresh</servlet-name>
<url-pattern>/Refresh</url-pattern>
</servlet-mapping>
....
现在使用URL http:// localhost:8080/Refresh调用此servlet,它将显示每5秒后的当前系统时间,如下所示。 只需运行servlet并等待查看结果 -
<h1 align="center">Auto Page Refresh using Servlet</h1>
<p>Current Time is: 9:44:50 PM</p>
Servlets - Sending Email
使用Servlet发送电子邮件很简单,但首先应该在您的计算机上安装JavaMail API和Java Activation Framework (JAF) 。
您可以从Java的标准网站下载最新版本的JavaMail (Version 1.2) 。
您可以从Java的标准网站下载最新版本的JAF (Version 1.1.1) 。
下载并解压缩这些文件,在新创建的顶级目录中,您将找到两个应用程序的jar文件。 您需要在CLASSPATH中添加mail.jar和activation.jar文件。
发送简单电子邮件
以下是从您的计算机发送简单电子邮件的示例。 这里假设您的localhost已连接到互联网并且足以发送电子邮件。 同时确保CLASSPATH中的Java Email API包和JAF包中的所有jar文件都可用。
// File Name SendEmail.java
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;
public class SendEmail extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Recipient's email ID needs to be mentioned.
String to = "abcd@gmail.com";
// Sender's email ID needs to be mentioned
String from = "web@gmail.com";
// Assuming you are sending email from localhost
String host = "localhost";
// Get system properties
Properties properties = System.getProperties();
// Setup mail server
properties.setProperty("mail.smtp.host", host);
// Get the default Session object.
Session session = Session.getDefaultInstance(properties);
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
try {
// Create a default MimeMessage object.
MimeMessage message = new MimeMessage(session);
// 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);
String title = "Send Email";
String res = "Sent message successfully....";
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor = \"#f0f0f0\">\n" +
"<h1 align = \"center\">" + title + "</h1>\n" +
"<p align = \"center\">" + res + "</p>\n" +
"</body>
</html>"
);
} catch (MessagingException mex) {
mex.printStackTrace();
}
}
}
现在让我们编译上面的servlet并在web.xml中创建以下条目
....
<servlet>
<servlet-name>SendEmail</servlet-name>
<servlet-class>SendEmail</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SendEmail</servlet-name>
<url-pattern>/SendEmail</url-pattern>
</servlet-mapping>
....
现在使用URL http:// localhost:8080/SendEmail调用此servlet,该URL将向给定的电子邮件ID abcd@gmail.com发送电子邮件,并显示以下响应 -
<h1 align="center">Send Email</h1>
<p align="center">Sent message successfully....</p>
如果您要向多个收件人发送电子邮件,则可以使用以下方法指定多个电子邮件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已连接到互联网并且足以发送电子邮件。 同时,确保CLASSPATH中的Java Email API包和JAF包中的所有jar文件都可用。
此示例与前一个示例非常相似,不同之处在于我们使用setContent()方法设置第二个参数为“text/html”的内容,以指定HTML内容包含在消息中。
使用此示例,您可以发送与您喜欢的HTML内容一样大的内容。
// File Name SendEmail.java
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;
public class SendEmail extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Recipient's email ID needs to be mentioned.
String to = "abcd@gmail.com";
// Sender's email ID needs to be mentioned
String from = "web@gmail.com";
// Assuming you are sending email from localhost
String host = "localhost";
// Get system properties
Properties properties = System.getProperties();
// Setup mail server
properties.setProperty("mail.smtp.host", host);
// Get the default Session object.
Session session = Session.getDefaultInstance(properties);
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
try {
// Create a default MimeMessage object.
MimeMessage message = new MimeMessage(session);
// 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);
String title = "Send Email";
String res = "Sent message successfully....";
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor = \"#f0f0f0\">\n" +
"<h1 align = \"center\">" + title + "</h1>\n" +
"<p align = \"center\">" + res + "</p>\n" +
"</body>
</html>"
);
} catch (MessagingException mex) {
mex.printStackTrace();
}
}
}
编译并运行上面的servlet以在给定的电子邮件ID上发送HTML消息。
在电子邮件中发送附件
以下是从您的计算机发送包含附件的电子邮件的示例。 这里假设您的localhost已连接到互联网并且足以发送电子邮件。
// File Name SendEmail.java
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;
public class SendEmail extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Recipient's email ID needs to be mentioned.
String to = "abcd@gmail.com";
// Sender's email ID needs to be mentioned
String from = "web@gmail.com";
// Assuming you are sending email from localhost
String host = "localhost";
// Get system properties
Properties properties = System.getProperties();
// Setup mail server
properties.setProperty("mail.smtp.host", host);
// Get the default Session object.
Session session = Session.getDefaultInstance(properties);
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
try {
// Create a default MimeMessage object.
MimeMessage message = new MimeMessage(session);
// 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 multipar 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";
String res = "Sent message successfully....";
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor = \"#f0f0f0\">\n" +
"<h1 align = \"center\">" + title + "</h1>\n" +
"<p align = \"center\">" + res + "</p>\n" +
"</body>
</html>"
);
} catch (MessagingException mex) {
mex.printStackTrace();
}
}
}
编译并运行上面的servlet,将文件作为附件发送,并在给定的电子邮件ID上发送消息。
用户认证部分
如果需要向电子邮件服务器提供用户ID和密码以进行身份验证,则可以按如下方式设置这些属性 -
props.setProperty("mail.user", "myuser");
props.setProperty("mail.password", "mypwd");
其余的电子邮件发送机制将保持如上所述。
Servlets - Packaging
涉及WEB-INF子目录的Web应用程序结构是所有Java Web应用程序的标准,并由servlet API规范指定。 给定myapp的顶级目录名称。 以下是此目录结构的样子 -
/myapp
/images
/WEB-INF
/classes
/lib
WEB-INF子目录包含应用程序的部署描述符,名为web.xml。 所有HTML文件都应保存在顶级目录myapp 。 对于admin用户,您会发现ROOT目录为父目录。
在包中创建Servlet
WEB-INF/classes目录包含与其包名匹配的结构中的所有servlet类和其他类文件。 例如,如果您具有com.myorg.MyServlet的完全限定类名,则此servlet类必须位于以下目录中 -
/myapp/WEB-INF/classes/com/myorg/MyServlet.class
以下是使用包名com.myorg创建MyServlet类的示例
// Name your package
package com.myorg;
// Import required java libraries
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class MyServlet extends HttpServlet {
private String message;
public void init() throws ServletException {
// Do required initialization
message = "Hello World";
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Set response content type
response.setContentType("text/html");
// Actual logic goes here.
PrintWriter out = response.getWriter();
out.println("<h1>" + message + "</h1>");
}
public void destroy() {
// do nothing.
}
}
编译包中的Servlet
编译包中可用的类没有什么不同。 最简单的方法是将java文件保存在完全限定的路径中,如上所述,类将保存在com.myorg中。 您还需要在CLASSPATH中添加此目录。
假设您的环境设置正确,请进入《Tomcat-installationdirectory》/webapps/ROOT/WEB-INF/classes目录并编译MyServlet.java,如下所示
$ javac MyServlet.java
如果servlet依赖于任何其他库,则还必须在CLASSPATH上包含这些JAR文件。 我只包含了servlet-api.jar JAR文件,因为我没有在Hello World程序中使用任何其他库。
此命令行使用Sun Microsystems Java软件开发工具包(JDK)附带的内置javac编译器。 要使此命令正常工作,您必须在PATH环境变量中包含您正在使用的Java SDK的位置。
如果一切顺利,上面的编译将在同一目录中生成MyServlet.class文件。 下一节将解释如何在生产中部署已编译的servlet。
打包的Servlet部署
默认情况下,servlet应用程序位于路径
如果你有一个完全限定的com.myorg.MyServlet类名,那么这个servlet类必须位于WEB-INF/classes/com/myorg/MyServlet.class中,你需要在web.xml文件中创建以下条目在“Tomcat-installationdirectory”/ webapps/ROOT/WEB-INF/
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.myorg.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/MyServlet</url-pattern>
</servlet-mapping>
上面的条目将在web.xml文件中提供的
你差不多完成了,现在让我们使用
<h1 align="center">Hello World</h1>
Servlets - Debugging
测试/调试servlet总是很困难。 Servlet往往涉及大量的客户端/服务器交互,使得错误可能但很难重现。
以下是一些可能有助于您进行调试的提示和建议。
System.out.println()
System.out.println()很容易用作标记来测试某段代码是否正在执行。 我们也可以打印出变量值。 另外 -
由于System对象是核心Java对象的一部分,因此可以在任何地方使用它,而无需安装任何额外的类。 这包括Servlet,JSP,RMI,EJB,普通Bean和类以及独立应用程序。
在断点处停止技术会停止正常执行,因此需要更多时间。 而写入System.out并不会干扰应用程序的正常执行流程,这使得在时序至关重要时非常有价值。
以下是使用System.out.println()的语法 -
System.out.println("Debugging message");
上述语法生成的所有消息都将记录在Web服务器日志文件中。
消息记录
使用正确的日志记录方法使用标准日志记录方法记录所有调试,警告和错误消息始终是个好主意。 我使用log4J来记录所有消息。
Servlet API还提供了一种使用log()方法输出信息的简单方法,如下所示 -
// Import required java libraries
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class ContextLog extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, java.io.IOException {
String par = request.getParameter("par1");
//Call the two ServletContext.log methods
ServletContext context = getServletContext( );
if (par == null || par.equals(""))
//log version with Throwable parameter
context.log("No message received:", new IllegalStateException("Missing parameter"));
else
context.log("Here is the visitor's message: " + par);
response.setContentType("text/html");
java.io.PrintWriter out = response.getWriter( );
String title = "Context Log";
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor = \"#f0f0f0\">\n" +
"<h1 align = \"center\">" + title + "</h1>\n" +
"<h2 align = \"center\">Messages sent</h2>\n" +
"</body>
</html>"
);
} //doGet
}
ServletContext将其文本消息记录到servlet容器的日志文件中。 使用Tomcat,这些日志可以在
日志文件确实指示了新出现的错误或问题的频率。 因此,最好在异常的catch子句中使用log()函数,这通常不会发生。
使用JDB调试器
您可以使用用于调试applet或应用程序的相同jdb命令来调试servlet。
为了调试servlet,我们调试sun.servlet.http.HttpServer并仔细观察HttpServer执行servlet以响应从浏览器发出的HTTP请求。 这与applet的调试方式非常相似。 不同之处在于,对于applet,正在调试的实际程序是sun.applet.AppletViewer。
大多数调试器通过自动知道如何调试applet来隐藏这个细节。 在他们对servlet执行相同操作之前,您必须通过执行以下操作来帮助您的调试器 -
设置调试器的类路径,以便它可以找到sun.servlet.http.Http-Server和相关的类。
设置调试器的类路径,以便它也可以找到您的servlet和支持类,通常是server_root/servlets和server_root/classes。
您通常不希望在类路径中使用server_root/servlet,因为它会禁用servlet重新加载。 但是,这种包含对于调试很有用。 它允许调试器在HttpServer中的自定义servlet加载器加载servlet之前在servlet中设置断点。
设置正确的类路径后,开始调试sun.servlet.http.HttpServer。 您可以在任何您想调试的servlet中设置断点,然后使用Web浏览器向HttpServer请求给定的servlet(http:// localhost:8080/servlet/ServletToDebug)。 您应该看到在断点处停止执行。
使用评论
代码中的注释可以通过各种方式帮助调试过程。 在调试过程中,可以通过许多其他方式使用注释。
Servlet使用Java注释,单行(// ...)和多行(/ * ... * /)注释可用于临时删除部分Java代码。 如果错误消失,请仔细查看您刚评论的代码并找出问题所在。
客户端和服务器标头
有时,当servlet的行为不符合预期时,查看原始HTTP请求和响应很有用。 如果您熟悉HTTP的结构,则可以阅读请求和响应,并确切了解这些标头的确切内容。
重要的调试技巧
以下列出了一些有关servlet调试的更多调试技巧 -
请记住,server_root/classes不会重新加载,而server_root/servlets可能会重新加载。
请求浏览器显示其正在显示的页面的原始内容。 这有助于识别格式问题。 它通常是“视图”菜单下的一个选项。
通过强制完全重新加载页面,确保浏览器不缓存先前请求的输出。 使用Netscape Navigator,使用Shift-Reload; 使用Internet-Refresh使用Shift-Refresh。
验证servlet的init()方法是否采用ServletConfig参数并立即调用super.init(config)。
Servlets - Internationalization
在我们开始之前,让我解释一下三个重要的术语 -
Internationalization (i18n) - 这意味着使网站能够提供翻译成访问者语言或国籍的不同版本的内容
Localization (l10n) - 这意味着向网站添加资源以适应特定的地理或文化区域。
locale - 这是一个特定的文化或地理区域。 它通常被称为语言符号,后跟一个由下划线分隔的国家/地区符号。 例如,“en_US”表示美国的英语区域设置。
在建立全球网站时,应该注意许多项目。 本教程不会为您提供有关此内容的完整详细信息,但它会为您提供一个很好的示例,说明如何通过区分其位置(即区域设置)以不同语言向Internet社区提供您的网页。
servlet可以根据请求者的语言环境获取站点的相应版本,并根据本地语言,文化和要求提供适当的站点版本。 以下是返回Locale对象的请求对象的方法。
java.util.Locale request.getLocale()
检测区域设置
以下是重要的区域设置方法,您可以使用它们来检测请求者的位置,语言和当前区域设置。 以下所有方法都显示在请求者的浏览器中设置的国家名称和语言名称。
Sr.No. | 方法和描述 |
---|---|
1 | String getCountry() 此方法以ISO 3166 2字母格式为此区域设置返回大写的国家/地区代码。 |
2 | String getDisplayCountry() 此方法返回适合显示给用户的区域设置国家/地区的名称。 |
3 | String getLanguage() 此方法以ISO 639格式为此语言环境返回小写的语言代码。 |
4 | String getDisplayLanguage() 此方法返回适合显示给用户的语言环境语言的名称。 |
5 | String getISO3Country() 此方法返回此区域设置国家/地区的三个字母缩写。 |
6 | String getISO3Language() 此方法返回此语言环境语言的三个字母缩写。 |
例子 (Example)
此示例显示如何显示请求的语言和关联国家/地区 -
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.Locale;
public class GetLocale extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//Get the client's Locale
Locale locale = request.getLocale();
String language = locale.getLanguage();
String country = locale.getCountry();
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String title = "Detecting Locale";
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor = \"#f0f0f0\">\n" +
"<h1 align = \"center\">" + language + "</h1>\n" +
"<h2 align = \"center\">" + country + "</h2>\n" +
"</body>
</html>"
);
}
}
语言设置
servlet可以输出用西欧语言编写的页面,如英语,西班牙语,德语,法语,意大利语,荷兰语等。这里设置ContentLanguage标题以正确显示所有字符非常重要。
第二点是使用HTML实体显示所有特殊字符,例如,“&#241;” 代表“ñ”和“&#161;” 代表“¡”如下:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.Locale;
public class DisplaySpanish extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
// Set spanish language code.
response.setHeader("Content-Language", "es");
String title = "En Español";
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor = \"#f0f0f0\">\n" +
"<h1>" + "En Español:" + "</h1>\n" +
"<h1>" + "¡Hola Mundo!" + "</h1>\n" +
"</body>
</html>"
);
}
}
区域特定日期
您可以使用java.text.DateFormat类及其静态getDateTimeInstance()方法来格式化特定于语言环境的日期和时间。 以下示例显示了如何格式化特定于给定语言环境的日期 -
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.Locale;
import java.text.DateFormat;
import java.util.Date;
public class DateLocale extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
//Get the client's Locale
Locale locale = request.getLocale( );
String date = DateFormat.getDateTimeInstance(DateFormat.FULL,
DateFormat.SHORT, locale).format(new Date( ));
String title = "Locale Specific Dates";
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor = \"#f0f0f0\">\n" +
"<h1 align = \"center\">" + date + "</h1>\n" +
"</body>
</html>"
);
}
}
区域特定货币
您可以使用java.txt.NumberFormat类及其静态getCurrencyInstance()方法以特定于语言环境的货币格式化数字,例如long或double类型。 以下是显示如何格式化给定区域设置的货币的示例 -
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.Locale;
import java.text.NumberFormat;
import java.util.Date;
public class CurrencyLocale extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
//Get the client's Locale
Locale locale = request.getLocale( );
NumberFormat nft = NumberFormat.getCurrencyInstance(locale);
String formattedCurr = nft.format(1000000);
String title = "Locale Specific Currency";
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor = \"#f0f0f0\">\n" +
"<h1 align = \"center\">" + formattedCurr + "</h1>\n" +
"</body>
</html>"
);
}
}
区域特定百分比
您可以使用java.txt.NumberFormat类及其静态getPercentInstance()方法来获取特定于语言环境的百分比。 以下是显示如何格式化特定于给定语言环境的百分比的示例 -
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.Locale;
import java.text.NumberFormat;
import java.util.Date;
public class PercentageLocale extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
//Get the client's Locale
Locale locale = request.getLocale( );
NumberFormat nft = NumberFormat.getPercentInstance(locale);
String formattedPerc = nft.format(0.51);
String title = "Locale Specific Percentage";
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor = \"#f0f0f0\">\n" +
"<h1 align = \"center\">" + formattedPerc + "</h1>\n" +
"</body>
</html>"
);
}
}
Servlets - Annotations
到目前为止,您已经了解了Servlet如何使用部署描述符(web.xml文件)将应用程序部署到Web服务器中。 Servlet API 3.0引入了一个名为javax.servlet.annotation的新包。 它提供了可用于注释servlet类的注释类型。 如果使用注释,则不需要部署描述符(web.xml)。 但是你应该使用tomcat7或更高版本的tomcat。
注释可以替换Web部署描述符文件(web.xml)中的等效XML配置,例如servlet声明和servlet映射。 Servlet容器将在部署时处理带注释的类。
Servlet 3.0中引入的注释类型是 -
Sr.No. | 注释和说明 |
---|---|
1 | @WebServlet 声明一个servlet。 |
2 | @WebInitParam 指定初始化参数。 |
3 | @WebFilter 声明servlet过滤器。 |
4 | @WebListener 声明WebListener |
5 | @HandlesTypes 声明ServletContainerInitializer可以处理的类类型。 |
6 | @HttpConstraint 此注释在ServletSecurity批注中用于表示要应用于所有HTTP协议方法的安全性约束,对于这些方法,ServletSecurity批注中不会出现相应的HttpMethodConstraint元素。 |
7 | @HttpMethodConstraint 此注释在ServletSecurity批注中用于表示特定HTTP协议消息的安全性约束。 |
8 | @MultipartConfig 可以在Servlet类上指定的注释,指示Servlet的实例需要符合multipart/form-data MIME类型的请求。 |
9 | @ServletSecurity 此注释用于Servlet实现类,以指定Servlet容器在HTTP协议消息上强制执行的安全性约束。 |
这里我们详细讨论了一些注释。
@WebServlet
@WebServlet用于声明带有容器的Servlet的配置。 下表包含用于WebServlet批注的属性列表。
Sr.No. | 属性和描述 |
---|---|
1 | String name Servlet的名称 |
2 | String[] value URL模式的数组 |
3 | String[] urlPatterns 此Filter应用的URL模式数组 |
4 | Int loadOnStartup 整数值为您提供启动顺序提示 |
5 | WebInitParam[] initParams 此Servlet的初始化参数数组 |
6 | Boolean asyncSupported 此Servlet支持异步操作 |
7 | String smallIcon 此Servlet的小图标(如果存在) |
8 | String largeIcon 此Servlet的大图标(如果存在) |
9 | String description 此Servlet的描述(如果存在) |
10 | String displayName 显示此Servlet的名称(如果存在) |
必须在注释的value或urlPattern属性中声明至少一个URL模式,但不能同时声明两者。
当URL模式是唯一设置的属性时,建议使用value属性,否则应使用urlPattern属性。
例子 (Example)
以下示例描述了如何使用@WebServlet批注。 它是一个显示文本Hello Servlet的简单servlet。
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(value = "/Simple")
public class Simple extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.print("<html><body>");
out.print("<h3>Hello Servlet</h3>");
out.print("</body></html>");
}
}
以通常的方式编译Simple.java并将您的类文件放在“Tomcat-installationdirectory”/ webapps/ROOT/WEB-INF/classes中。
现在尝试通过运行http://localhost:8080/Simple来调用任何servlet。 您将在网页上看到以下输出。
Hello servlet
@WebInitParam
@WebInitParam注释用于指定Servlet或Filter的初始化参数。 它在WebFilter或WebSevlet注释中使用。 下表包含用于WebInitParam批注的属性列表。
Sr.No. | 属性和描述 |
---|---|
1 | String name 初始化参数的名称 |
2 | String value 初始化参数的值 |
3 | String description 初始化参数的描述 |
例子 (Example)
以下示例描述了如何使用@WeInitParam注释以及@WebServlet注释。 它是一个简单的servlet,它显示文本Hello Servlet和字符串值Hello World! 它们取自init参数。
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(value = "/Simple", initParams = {
@WebInitParam(name = "foo", value = "Hello "),
@WebInitParam(name = "bar", value = " World!")
})
public class Simple extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.print("<html><body>");
out.print("<h3>Hello Servlet</h3>");
out.println(getInitParameter("foo"));
out.println(getInitParameter("bar"));
out.print("</body></html>");
}
}
以通常的方式编译Simple.java并将您的类文件放在“Tomcat-installationdirectory”;/webapps/ROOT/WEB-INF/classes中。
现在尝试通过运行http://localhost:8080/Simple来调用任何servlet。 您将在网页上看到以下输出。
Hello Servlet
Hello World!
@Webfilter
这是用于声明servlet过滤器的注释。 它在部署时由容器处理,并且相应的过滤器应用于指定的URL模式,servlet和调度程序类型。
@WebFilter注释定义了Web应用程序中的过滤器。 此批注在类上指定,并包含有关正在声明的过滤器的元数据。 带注释的过滤器必须至少指定一个URL模式。 下表列出了用于WebFilter批注的属性。
Sr.No. | 属性和描述 |
---|---|
1 | String filterName 过滤器的名称 |
2 | String[] urlPatterns 提供过滤器适用的值数组或urlPatterns |
3 | DispatcherType[] dispatcherTypes 指定过滤器适用的调度程序(请求/响应)的类型 |
4 | String[] servletNames 提供一组servlet名称 |
5 | String displayName 过滤器的名称 |
6 | String description 过滤器的描述 |
7 | WebInitParam[] initParams 此过滤器的初始化参数数组 |
8 | Boolean asyncSupported 此过滤器支持异步操作 |
9 | String smallIcon 此过滤器的小图标(如果存在) |
10 | String largeIcon 此过滤器的大图标(如果存在) |
例子 (Example)
以下示例描述了如何使用@WebFilter批注。 它是一个简单的LogFilter,它在控制台上显示Init-param test-param和当前时间戳。 这意味着,过滤器就像请求和响应之间的接口层。 这里我们使用“/ *”表示urlPattern。 这意味着,此过滤器适用于所有servlet。
import java.io.IOException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.*;
import java.util.*;
// Implements Filter class
@WebFilter(urlPatterns = {"/*"}, initParams = {
@WebInitParam(name = "test-param", value = "Initialization Paramter")})
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 IOException, ServletException {
// Log the current timestamp.
System.out.println("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*/
}
}
以通常的方式编译Simple.java并将您的类文件放在“Tomcat-installationdirectory”/ webapps/ROOT/WEB-INF/classes中。
现在尝试通过运行http://localhost:8080/Simple来调用任何servlet。 您将在网页上看到以下输出。
Hello Servlet
Hello World!
现在,打开servlet控制台。 在那里,您将找到init参数testparam的值以及current timestamp以及servlet通知消息。