您的位置:首页 > 编程语言

Servlet 编程基础

2018-01-09 20:47 211 查看
可参考博文 超文本传输协议HTTP

Servlet 概述

Servlet(Server Applet)是Java Servlet 的简称,称为小服务程序或服务连接器,用Java 编写的服务器端程序,主要功能在于交互式地浏览和修改数据,生成动态Web 内容。

从原理上讲,Servlet 可以响应任何类型的请求,但绝大多数情况下Servlet 只用来扩展基于HTTP 协议的Web 服务器。HTTP 定义的与服务器交互的方法有GET、POST、PUT和DELETE 等,其中最基本的是GET 与POST。HTTP-GET 与HTTP-POST 是使用HTTP 的标准协议动词,用于编码和传送变量名/变量值对参数,并使用相关的请求(Request)语义。每个HTTP-GET 与HTTP-POST 都由一系列的HTTP 请求头组成,这些请求头定义了客户端从服务器上请求了什么,而响应(Response)则是由一系列HTTP 应答头和应答数据组成,如果请求成功,则返回应答数据。

其中GET 与POST 的主要区别如下

GET 方法是默认的浏览器向Web 服务传递信息的方法,它会产生一个 很长的字符串,出现在浏览器的地址栏中。而POST 方式则是把数据作为一个单独的消息以标准输出的形式传到后台程序,所以使用POST 不会将数据显示在地址栏中。

对于GET 方式,服务端用Request,QueryString 获取变量的值;对于POST 方式,服务端使用Request,Form 获取提交的数据。

GET 方式受传输数据字节的限制,POST 方式不受限制。

狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。下面是Servlet 架构图。



Servlet 与 CGI

Servlet 与CGI(Common Gateway Interfece,公共网关接口)都是服务端组件,通常情况下可以实现相同的效果。但是与CGI 相比,Servlet 有以下的相关优势

性能更好

由于Servlet 是由Java 语言实现的,所以是独立于平台的。

Servlet 在Web 服务器的地址空间内执行,没有必要再创建一个单独的进程来处理每个客户端的请求。

Java 类库的全部功能对于Servlet 来说都是可用的。

Servlet 与 JSP

SUN 首先发展出 Servlet,其功能比较强劲,体系设计也很先进,只是,它输出HTML 语句还是采用了老的 CGI 方式,是一句一句输出,所以,编写和修改 HTML 非常不方便。

Java Server Pages(JSP)是一种实现普通静态HTML 和动态 HTML 混合编码的技术,JSP 并没有增加任何本质上不能用 Servlet 实现的功能。但是,在 JSP 中编写静态HTML 更加方便,不必再用 println语 句来输出每一行 HTML 代码。更重要的是,借助内容和外观的分离,页面制作中不同性质的任务可以方便地分开:比如,由页面设计者进行 HTML设计,同时留出供 Servlet 程序员插入动态内容的空间。

JSP 在首次被访问的时候会被服务器转换为Servlet ,在以后的运行中,容器直接调用这个Servlet,而不再访问JSP 页面。所以来说JSP 的本质就是Servlet。

总而言之,JSP 的本质是Servlet ,由于在Servlet 中开发HTML 代码不方便,所以JSP 应运而生。我们一般使用JSP 作数据页面展示,使用Servlet 来处理客户端与服务端的交互。

Servlet 的继承结构

Servlet 接口:定义了一个servlet 应该具有的方法(如init、service 与destroy 方法等),所有的Servlet都应该直接或间接实现此接口。

GenericServlet 抽象类:通用Servlet,对Servlet 接口的默认实现,这是一个抽象类,其中的大部分方法都做了默认实现,只有service 方法是一个抽象方法需要继承者自己实现。

HttpServlet 抽象类:对HTTP 协议进行了优化的Servlet,继承自GenericServlet 类,并且实现了其中的service 抽象方法,默认的实现中判断了请求的请求方式,并根据请求方式的不同分别调用不同的doXXX() 方法。通常我们编写Servlet 直接继承该抽象类即可。

下面就结合源码来看一下HttpServlet 中service() 方法的实现(代码逻辑很清晰就不再做具体的分析)

protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {

String method = req.getMethod();    //返回一个字符串形式的请求方式

if (method.equals(METHOD_GET)) {    //如果当前客户端发起的是GET 方式的请求,就调用doGet() 方法
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < (lastModified / 1000 * 1000)) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {    //如果客户端发起的是POST方式的请求,调用doPost() 方法
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 {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}


Servlet 的生命周期

Servlet 运行于服务器上的Web 容器中(比如Tomcat 与Jboss 等)。应用服务器中用于管理Java 组件的部分被称为Servlet 容器。当Servlet 被部署在应用服务器以后,由容器控制Servlet 的生命周期。Servlet 在第一次被请求的时候加载和实例化。Servlet 一旦被加载,当响应结束后会一直驻留在内存中等待下一次请求,直至应用服务器关闭或者重新启动。所以第一次访问Servlet 花费的时间要大于以后访问该Servlet 所用的时间。当容器作内存回收时,Servlet 可能会被删除。



1. 加载Servlet 类,创建该类的实例。每一个用户都会产生一个新的线程(所以说Servlet 是线程不安全的)。

2. Servlet 通过init() 方法进行初始化。

3. Servlet 调用service(req,resp) 方法,根据请求方式调用对应的do×××() 方法,来处理客户端的请求。

4. Servlet 通过destroy() 方法终止。

5. Servlet 被JVM 的垃圾回收机制收集。

Servlet 的调用过程

可参考图如下(百度百科)



为了更好的理解,这里通过一个例子来具体讲述其中的过程。

新建一个Servlet,如下(当客户端请求该Servlet 时,输出一个表情符号)

package com.jas.test;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class ServletTest extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getWriter().write("O(?_?)O~");
}

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request,response);
}
}


在web.xml 中配置上面Servlet 的相关信息,如下

PS:Tomcat 7 及以上的版本不需要再做相应配置,通过@WebServlet(“/XXX”) 注解就可以实现配置文件的作用。这里为了演示效果仍然使用配置文件的形式。

<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.jas.test.ServletTest</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>


效果如下



调用过程分析如下(HTTP 请求报文与响应报文数据摘自IE 浏览器),过程中省略了Servlet 实例化的过程。



参考资料:

《JavaEE编程及应用开发》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: