Servlet
1. Servlet简介
1.1 什么是servlet
概念: Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。
定位: Java Servlet用Java编写的服务器端程序(web application)。
作用: 其主要功能在于交互式地浏览和修改数据,生成动态Web内容。
理解: 狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,我们将Servlet理解为后者。
1.2 Servlet定位图
1.3 Servlet核心作用
参考上图
1.4 Servlet标准 API核心包(在线文档)
Servlet API有以下3个Java包:
javax.servlet(重点):其中包含定义Servlet和Servlet容器之间的类和接口
javax.servlet.http(重点):其中包含定义HTTP Servlet和Servlet容器之间的类和接口
javax.servlet.annotation:其中包含标注Servlet,Filter,Listener的注解
备注:JavaWeb中主要关注javax.servlet和javax.servlet.http的成员。
参考http://tomcat.apache.org/tomcat-7.0-doc/servletapi/index.html
2. Servlet常见方法与生命周期
2.1 概览
Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:
- Servlet 通过调用 init () 方法进行初始化。
- Servlet 调用 service() 方法来处理客户端的请求。
- Servlet 通过调用 destroy() 方法终止(结束)。
- 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
2.2 HttpServlet处理Http请求
- Servlet的service()方法是请求的入口方法,HttpServlet实现service()方法在这个入口方法中根据不同的Http请求方法(如GET、POST请求)调用不同的方法。
- 大多数应用程序都是要于HTTP结合起来使用。这意味着可以利用HTTP提供的特性。javax.servlet.http包是Servlet API中的第二个包,其中包含了用于编写Servlet应用程序的类和接口,并且许多类型都覆写了javax.servlet 中的类型。
- HttpServlet类覆盖了 javax.servlet.GenericServlet 类。使用HttpServlet时,需要使用代表Servlet请求和Servlet响应的 HttpServletRequest 和 HttpServletResponse 对象。
HttpServlet中的Service方法会检验用来发送请求的HTTP方法(通过调用request.getMethod() ), 并调用以下方法之一:
方法名称 | 重要性 |
---|---|
doGet | 重要且常用 |
doPost | 重要且常用 |
doHead | 了解 |
doPut | 了解 |
doTrace | 了解 |
doOptions | 了解 |
doDelete | 了解 |
这7中方法,每一种方法都表示一个HTTP方法, doGet 和 doPost 是最常用的。
而service方法在内部已经对收到的http请求的方法做了分类,从而让请求可以路由到不同的具体方法(如:doGet)
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
...
if (lastModified == -1) {
doGet(req, resp);
} else {
...
if (ifModifiedSince < lastModified) {
...
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
...
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
} else {
...
}
}
因此,实际在编写servlet程序的时候,不再需要覆盖Service方法了,只要覆盖doGet或者doPost即可。
2.3 细节
A. init 方法被设计成只调用一次。
它在第一次创建 Servlet 时被调用,在后续每次用户请求时不再调用。因此,它是用于一次性初始化,就像 Applet的 init 方法一样。
Servlet 创建于用户第一次调用对应于该 Servlet 的 URL 时,但是也可以指定 Servlet 在服务器第一次启动时被加载。
当用户调用一个 Servlet 时,就会创建一个 Servlet 实例,每一个用户请求都会产生一个新的线程,适当的时候移交给 doGet 或 doPost 方法。init() 方法简单地创建或加载一些数据,这些数据将被用于 Servlet 的整个生命周期。init 方法的定义如下:
public void init() throws ServletException {
// 初始化代码...
}
B. 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() 方法是每次服务请求中最常用的方法。
C. destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。
destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。
在调用 destroy() 方法之后,servlet 对象被标记为垃圾回收。destroy 方法定义如下所示:
public void destroy() {
// 终止化代码...
}
3. Servlet 客户端 HTTP 请求
3.1 客户端Request常见报头
当浏览器请求网页时,它会向 Web 服务器发送特定信息,这些信息不能被直接读取,因为这些信息是作为 HTTP请求的头的一部分进行传输的。我们可以查看 HTTP 协议了解更多相关信息。
以下是来自于浏览器端的重要头信息,我们可以在 Web 编程中频繁使用
头信息 | 描述 |
---|---|
Accept | 这个头信息指定浏览器或其他客户端可以处理的 MIME 类型。值 image/png 或image/jpeg 是最常见的两种可能值。 |
Accept-Charset | 这个头信息指定浏览器可以用来显示信息的字符集。例如 ISO-8859-1。 |
Accept-Encoding | 这个头信息指定浏览器知道如何处理的编码类型。值 gzip 或 compress 是最常见的两种可能值。 |
Accept-Language | 这个头信息指定客户端的首选语言,在这种情况下,Servlet 会产生多种语言的结果。例 如,en、en-us、ru 等。 |
Authorization | 这个头信息用于客户端在访问受密码保护的网页时识别自己的身份。 |
Connection | 这个头信息指示客户端是否可以处理持久 HTTP 连接。持久连接允许客户端或其他浏览器通过单个请求来检索多个文件。值 Keep-Alive 意味着使用了持续连接。 |
Content-Length | 这个头信息只适用于 POST 请求,并给出 POST 数据的大小(以字节为单位)。 |
Cookie | 这个头信息把之前发送到浏览器的 cookies 返回到服务器。 |
Host | 这个头信息指定原始的 URL 中的主机和端口。 |
If-Modified-Since | 这个头信息表示只有当页面在指定的日期后已更改时,客户端想要的页面。如果没有新的结果可以使用,服务器会发送一个 304 代码,表示 Not Modified 头信息。 |
If-Unmodified-Since | 这个头信息是 If-Modified-Since 的对立面,它指定只有当文档早于指定日期时,操作才会成功。 |
Referer | 这个头信息指示所指向的 Web 页的 URL。例如,如果您在网页 1,点击一个链接到网页2,当浏览器请求网页 2 时,网页 1 的 URL 就会包含在 Referer 头信息中。 |
User-Agent | 这个头信息识别发出请求的浏览器或其他客户端,并可以向不同类型的浏览器返回不同的内容。 |
3.2 操作 HTTP Request头的方法
下面的方法可用在 Servlet 程序中读取 HTTP 头。这些方法通过 HttpServletRequest 对象使用。
方法 | 描述 |
---|---|
Cookie[] getCookies() | 返回一个数组,包含客户端发送该请求的所有的 Cookie 对象。 |
Enumeration getHeaderNames() | 返回一个枚举,包含在该请求中包含的所有的头名。 |
Enumeration getParameterNames() | 返回一个 String 对象的枚举,包含在该请求中包含的参数的名称。 |
HttpSession getSession() | 返回与该请求关联的当前 session 会话,或者如果请求没有 session 会话,则创建一个。 |
HttpSession getSession(boolean create) | 返回与该请求关联的当前 HttpSession,或者如果没有当前会话,且创建是真的,则返回一个新的 session 会话。 |
String getCharacterEncoding() | 返回请求主体中使用的字符编码的名称。 |
String getContentType() | 返回请求主体的 MIME 类型,如果不知道类型则返回 null。 |
String getContextPath() | 返回指示请求上下文的请求 URI 部分。 |
String getHeader(String name) | 以字符串形式返回指定的请求头的值。 |
String getMethod() | 返回请求的 HTTP 方法的名称,例如,GET、POST 或 PUT。 |
String getParameter(String name) | 以字符串形式返回请求参数的值,或者如果参数不存在则返回 null。 |
String getProtocol() | 返回请求协议的名称和版本。 |
String getQueryString() | 返回包含在路径后的请求 URL 中的查询字符串。 |
String getRemoteUser() | 如果用户已通过身份验证,则返回发出请求的登录用户,或者如果用户未通过身份验证,则返回 null。 |
String getRequestURI() | 从协议名称直到 HTTP 请求的第一行的查询字符串中,返回该请求的 URL 的一部分。 |
String getRequestedSessionId() | 返回由客户端指定的 session 会话 ID。 |
String[] getParameterValues(String name) | 返回一个字符串对象的数组,包含所有给定的请求参数的值,如果参数不存在则返回 null。 |
int getContentLength() | 以字节为单位返回请求主体的长度,并提供输入流,或者如果长度未知则返回 -1。 |
3.3 代码示例
- 安装之前的内容,建立maven web项目
- 配置web.xml
- 后面就可以直接编写代码了
web.xml配置说明
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1"
metadata-complete="true">
<servlet>
<servlet-name>Hello</servlet-name>
<servlet-class>HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Hello</servlet-name>
<url-pattern>/hello-servlet</url-pattern>
</servlet-mapping>
</web-app>
核心方法使用1-基本方法使用:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
public class HelloServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException,IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String method = request.getMethod();//返回请求的 HTTP 方法的名称
String encoding = request.getCharacterEncoding();//返回请求主体中使用的字符编码的名称
String url = request.getContextPath();//返回指示请求上下文的请求 URI 部分
String contentType = request.getContentType();//返回请求主体的 MIME 类型,如果不知道类型则返回 null
String title = "HTTP Function Test!";
String docType = "<!doctype html>\n";
out.println(docType + "<html>\n" +
"<head><title>" +title+ "</title></head>\n" +
"<body>"+
"<h3> Method: " +method+ "</h3>" +"<h3> encoding: " +encoding+ "</h3>" +
"<h3> url: " +url+ "</h3>" +
"<h3> contentType: " +contentType+ "</h3>" +
"</body>"+
"</html>");
}
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
doGet(request,response);
}
}
运行结果
核心方法使用2-表单
先编写我们基本的index.html
<!DOCTYPE html>
<html lang="en">
<body>
<form action="hello-servlet" method="GET"> <!--先使用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>
编写处理Servlet逻辑
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class HelloServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException,IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String method = request.getMethod();
String first_name = request.getParameter("first_name");
String last_name = request.getParameter("last_name");
String title = "HTTP Function Test!";
String docType = "<!doctype html>\n";
out.println(docType + "<html>\n" +
"<head><title>" +title+ "</title></head>\n" +
"<body>"+
"<h3> method: " +method+ "</h3>" +
"<h3> first_name: " +first_name+ "</h3>" +
"<h3> last_name: " +last_name+ "</h3>" +
"</body>"+
"</html>");
}
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException{
doGet(request,response);
}
}
验证结果:
-
先获取表单,填充参数
-
GET提交,参数回显到url中!!
-
改成POST请求,修改index.html
...
<form action="hello-servlet" method="POST">
...
核心方法使用3-获取HTTP Request头部信息
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
public class HelloServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException,IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String title = "HTTP Header Request";
String docType = "<!doctype html\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n"+
"<body>\n" +
"<h1 align=\"center\">" + title + "</h1>\n" +
"<table width=\"100%\" border=\"2\" align=\"center\">\n" +
"<tr>\n" +
"<th>Header name</th><th>Header value</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>");
}
@Override
public void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException{
doGet(request,response);
}
}
运行结果:
4. Servlet 服务器 HTTP 响应
4.1 服务器端Response常见报头
下表总结了从 Web 服务器端返回到浏览器的最有用的 HTTP 1.1 响应报头,您会在 Web 编程中频繁地使用它们:
头信息 | 描述 |
---|---|
Allow | 这个头信息指定服务器支持的请求方法(GET、POST 等)。 |
Cache-Contro | 这个头信息指定响应文档在何种情况下可以安全地缓存。可能的值有:public、private 或no-cache 等。Public 意味着文档是可缓存,Private 意味着文档是单个用户私用文档,且只能存储在私有(非共享)缓存中,no-cache 意味着文档不应被缓存。 |
Connection | 这个头信息指示浏览器是否使用持久 HTTP 连接。值 close 指示浏览器不使用持久 HTTP 连接,值 keep-alive 意味着使用持久连接。 |
Content-Disposition | 这个头信息可以让您请求浏览器要求用户以给定名称的文件把响应保存到磁盘。 |
Content-Encoding | 在传输过程中,这个头信息指定页面的编码方式。 |
Content-Language | 这个头信息表示文档编写所使用的语言。例如,en、en-us、ru 等。 |
Content-Length | 这个头信息指示响应中的字节数。只有当浏览器使用持久(keep-alive)HTTP 连接时才需要这些信息。 |
Content-Type | 这个头信息提供了响应文档的 MIME(Multipurpose Internet Mail Extension)类型。 |
Expires | 这个头信息指定内容过期的时间,在这之后内容不再被缓存。 |
Last- Modified | 这个头信息指示文档的最后修改时间。然后,客户端可以缓存文件,并在以后的请求中通过If-Modified-Since 请求头信息提供一个日期。 |
Location | 这个头信息应被包含在所有的带有状态码的响应中。在 300s 内,这会通知浏览器文档的地址。浏览器会自动重新连接到这个位置,并获取新的文档。 |
Refresh | 这个头信息指定浏览器应该如何尽快请求更新的页面。您可以指定页面刷新的秒数。 |
Retry-After | 这个头信息可以与 503(Service Unavailable 服务不可用)响应配合使用,这会告诉客户端多久就可以重复它的请求。 |
Set-Cookie | 这个头信息指定一个与页面关联的 cookie。 |
4.2 操作HTTP Response头的方法
下面的方法可用于在 Servlet 程序中设置 HTTP 响应报头。这些方法通过 HttpServletResponse 对象可用。
序号 | 方法 & 描述 |
---|---|
String encodeRedirectURL(String url) | 为 sendRedirect 方法中使用的指定的 URL 进行编码,或者如果编码不是必需的,则返回 URL 未改变。 |
String encodeURL(String url) | 对包含 session 会话 ID 的指定 URL 进行编码,或者如果编码不是必需的,则返回 URL 未改变。 |
boolean isCommitted() | 返回一个布尔值,指示响应是否已经提交。 |
void addCookie(Cookie cookie) | 把指定的 cookie 添加到响应。 |
void addDateHeader(String name, long date) | 添加一个带有给定的名称和日期值的响应报头。 |
void addHeader(String name, String value) | 添加一个带有给定的名称和值的响应报头。 |
void addIntHeader(String name, int value) | 添加一个带有给定的名称和整数值的响应报头。 |
void sendRedirect(String location) | 使用指定的重定向位置 URL 发送临时重定向响应到客户端。 |
void setCharacterEncoding(String charset) | 设置被发送到客户端的响应的字符编码(MIME 字符集)例如,UTF-8。 |
void setContentLength(int len) | 设置在 HTTP Servlet 响应中的内容主体的长度,该方法设置 HTTPContent-Length 头。 |
void setContentType(Stringtype) | 如果响应还未被提交,设置被发送到客户端的响应的内容类型。 |
void setDateHeader(String name, long date) | 设置一个带有给定的名称和日期值的响应报头。 |
void setHeader(String name, String value) | 设置一个带有给定的名称和值的响应报头。 |
void setIntHeader(String name, int value) | 设置一个带有给定的名称和整数值的响应报头。 |
void setStatus(int sc) | 为该响应设置状态码。 |
4.3 代码示例
核心方法使用-自动刷新页面
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Calendar;
import java.util.GregorianCalendar;
// 扩展 HttpServlet 类
public class HelloServlet extends HttpServlet {
// 处理 GET 方法请求的方法
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置刷新自动加载时间为 1 秒
response.setIntHeader("Refresh", 1); //设置一个带有给定的名称和整数值的响应报头。
// 设置响应内容类型
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 set";
String docType = "<!doctype html>\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n"+
"<body>\n" +
"<h1 align=\"center\">" + title + "</h1>\n" +
"<p>current time: " + CT + "</p>\n");
}
// 处理 POST 方法请求的方法
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}