文章目录
1.什么是Servlet
Servlet是sun公司提供的一门用于开发动态web资源的技术。
Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:
1、编写一个Java类,实现servlet接口。
2、把开发好的Java类部署到web服务器中。
按照一种约定俗成的称呼习惯,通常我们也把实现了servlet接口的java程序,称之为Servlet。
servlet就是你写在容器(如tomcat)里的动态资源,远程客户端点击或者一个url请求会封装成一个http请求,到你的服务端后由容器解析http请求,并封装为java
servlet请求和响应,最后放进servlet的service方法根据请求作出服务。
2.Servlet的生命周期
Servlet程序是由WEB服务器调用,web服务器收到客户端的Servlet访问请求后:
①Web服务器首先检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第④步,否则,执行第②步。
②装载并创建该Servlet的一个实例对象。
③调用Servlet实例对象的init()方法。
④创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。
⑤WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。
3.Servlet 容器
Tomcat 的容器等级中,Context 容器是直接管理 Servlet 在容器中的包装类 Wrapper,所以 Context 容器如何运行将直接影响 Servlet 的工作方式。
Tomcat 容器模型
从上图可以看出 Tomcat 的容器分为四个等级,真正管理 Servlet 的容器是 Context 容器,一个 Context 对应一个 Web 工程。
4.tomcat和servlet的关系
- Tomcat 是Web应用服务器,是一个Servlet/JSP容器. Tomcat 作为Servlet容器,负责处理客户请求,把请求传送给Servlet,并将Servlet的响应传送回给客户.而Servlet是一种运行在支持Java语言的服务器上的组件. Servlet最常见的用途是扩展Java Web服务器功能,提供非常安全的,可移植的,易于使用的CGI替代品.
- 从http协议中的请求和响应可以得知,浏览器发出的请求是一个请求文本,而浏览器接收到的也应该是一个响应文本。但是在上面这个图中,并不知道是如何转变的,只知道浏览器发送过来的请求也就是request,我们响应回去的就用response。忽略了其中的细节,现在就来探究一下。
- Tomcat将http请求文本接收并解析,然后封装成HttpServletRequest类型的request对象,所有的HTTP头数据读可以通过request对象调用对应的方法查询到。
- Tomcat同时会要响应的信息封装为HttpServletResponse类型的response对象,通过设置response属性就可以控制要输出到浏览器的内容,然后将response交给tomcat,tomcat就会将其变成响应文本的格式发送给浏览器
Java Servlet API 是Servlet容器(tomcat)和servlet之间的接口,它定义了serlvet的各种方法,还定义了Servlet容器传送给Servlet的对象类,其中最重要的就是ServletRequest和ServletResponse。所以说我们在编写servlet时,需要实现Servlet接口,按照其规范进行操作。
5.servlet的体系结构
1.Servlet接口
在Servlet接口中定义了5个方法,其中3个方法都是由Servlet容器来调用的,容器会在Servlet的生命周期的不同阶段调用特定的方法:
- init(ServletConfig) —— 负责初始化Servlet对象,容器在创建好Servlet对象后,就会调用该方法;
- service(ServletRquest req, ServletResponse res) —— 负责相应客户的请求,为客户提供相应服务。当容器接受到客户端要求访问特定Servlet对象的请求时,就会调用该Servlet对象的service()方法;
- destroy() —— 负责释放Servlet对象占用的资源。当Servlet对象结束声明周期时,容器会调用此方法;
2.GenericServlet抽象类
GenericServlet抽象类为Servlet接口提供了通用实现,它与任何网络应用层协议无关。
GenericServlet除了实现了Servlet接口,还实现了ServletConfig接口和Serializable接口:
public abstract class GenericServlet
implements Servlet, ServletConfig, java.io.Serializable
- GenericServlet类实现了Servlet接口中的init(ServletConfig config)初始化方法。GenericServlet类有一个ServletConfig类型的private成员变量,当Servlet容器调用GenericServlet的init(ServletConfig)方法时,该方法使得私有变量引用由容器传入的ServletConfig对象。GenericServlet类还定义了一个不带参数的init()方法,init(ServletConfig)方法会调用此方法。因此在子类中重写init时,最好重写init()方法,若重写Init(ServletConfig)方法,还需要先调用父类的init(ServletConfig)方法(super.init(config))。
- GenericServlet类没有实现Servlet接口中的service()方法。service()方法是GenericServlet类中唯一的抽象方法,GenericServlet类的具体子类必须实现该方法。
3.HttpServlet抽象类
HttpServlet类是GenericServlet类的子类。HttpServlet类为Serlvet接口提供了与HTTP协议相关的通用实现,也就是说,HttpServlet对象适合运行在与客户端采用HTTP协议通信的Servlet容器或者Web容器中。
4.ServletRequest接口
ServletRequest表示来自客户端的请求;当Servlet容器接收到客户端要求访问特定Servlet的请求时,容器先解析客户端的原始请求数据,把它包装成一个ServletRequest对象。ServletRequest接口提供了一系列用于读取客户端的请求数据的方法,例如:
getContentLength() —— 返回请求正文的长度,如果请求正文的长度未知,则返回-1;
getContentType() —— 获得请求正文的MIME类型,如果请求正文的类型为止,则返回null;
getInputStream() —— 返回用于读取请求正文的输入流;
getLocalAddr() —— 返回服务端的IP地址;
getLocalName() —— 返回服务端的主机名;
getLocalPort() —— 返回服务端的端口号;
getParameters() —— 根据给定的请求参数名,返回来自客户请求中的匹配的请求参数值;
getProtocal() —— 返回客户端与服务器端通信所用的协议名称及版本号;
getReader() —— 返回用于读取字符串形式的请求正文的BufferReader对象;
getRemoteAddr() —— 返回客户端的IP地址
getRemoteHost() —— 返回客户端的主机名
getRemotePort() —— 返回客户端的端口号
5.HttpServletRequest接口
HttpServletRequest接口是ServletRequest接口的子接口。
HttpServletRequest接口提供了用于读取HTTP请求中的相关信息的方法:
getContextPath() —— 返回客户端请求方法的Web应用的URL入口,例如,如果客户端访问的URL为http://localhost:8080/helloapp/info,那么该方法返回“/helloapp”;
getCookies() —— 返回HTTP请求中的所有Cookie;
getHeader(String name) —— 返回HTTP请求头部的特定项;
getHeaderName() —— 返回一个Enumeration对象,它包含了HTTP请求头部的所有项目名;getMethod() —— 返回HTTP请求方式;
getRequestURL() —— 返回HTTP请求的头部的第一行中的URL;
getQueryString() —— 返回HTTP请求中的查询字符串,即URL中的“?”后面的内容;
6.ServletResponse接口
Servlet通过ServletResponse对象来生成响应结果。
ServletResponse接口定义了一系列与生成响应结果相关的方法,例如:
setCharacterEncoding() —— 设置相应正文的字符编码。响应正文的默认字符编码为ISO-8859-1;
setContentLength() —— 设置响应正文的长度;
setContentType() —— 设置响应正文的MIME类型;
getCharacterEncoding() —— 获得响应正文的字符编码
getContentType() —— 获得响应正文的MIME类型
setBufferSize() —— 设置用于存放响应正文数据的缓冲区的大小
getBufferSize() —— 获得用于存放响应正文数据的缓冲区的大小;
reset() —— 清空缓冲区内的正文数据,并且清空响应状态代码及响应头
resetBuffer() —— 仅仅清空缓冲区的正文数据,不清空响应状态代码及响应头;flushBuffer() —— 强制性地把缓冲区内的响应正文数据发送到客户端;
isCommitted() —— 返回一个boolean类型的值,如果为true,表示缓冲区内的数据已经提交给客户,即数据已经发送到客户端;
getOutputStream() —— 返回一个ServletOutputStream对象,Servlet用它来输出二进制的正文数据;
getWriter() —— 返回一个PrinterWriter对象,Servlet用它来输出字符串形式的正文数据;
ServletResponse中响应正文的默认MIME类型是text/plain,即纯文本类型,而HttpServletResponse中响应正文的默认MIME类型为text/html,即HTML文档类型。
为了提高输出数据的效率,ServletOutputStream和PrintWriter首先把数据写到缓冲区内。当缓冲区内的数据被提交给客户后,ServletResponse的isComitted方法返回true。在以下几种情况下,缓冲区内的数据会被提交给客户,即数据被发送到客户端:
- 当缓冲区内的数据已满时,ServletOutPutStream或PrintWriter会自动把缓冲区内的数据发送给客户端,并且清空缓冲区;
- Servlet调用ServletResponse对象的flushBuffer方法;
- Servlet调用ServletOutputStream或PrintWriter对象的flush方法或close方法;
为了确保SerlvetOutputStream或PrintWriter输出的所有数据都会被提交给客户,比较安全的做法是在所有数据都输出完毕后,调用ServletOutputStream或PrintWriter的close()方法(Tomcat中,会自动关闭)。
如果要设置响应正文的MIME类型和字符编码,必须先调用ServletResponse对象的setContentType()和setCharacterEncoding()方法,然后再调用ServletResponse的getOutputStream()或getWriter()方法,提交缓冲区内的正文数据;只有满足这样的操作顺序,所做的设置才能生效。
7.HttpServletResponse接口
HttpServletResponse接口提供了与HTTP协议相关的一些方法,Servlet可通过这些方法来设置HTTP响应头或向客户端写Cookie。
addHeader() —— 向HTTP响应头中加入一项内容
sendError() —— 向客户端发送一个代表特定错误的HTTP响应状态代码
setHeader() —— 设置HTTP响应头中的一项内容,如果在响应头中已经存在这项内容,则原来的设置被覆盖
setStatus() —— 设置HTTP响应的状态代码
addCookie() —— 向HTTP响应中加入一个Cookie
在HttpServletResponse接口中定义了一些代表HTTP响应状态代码的静态常量。
8.ServletConfig接口
当Servlet容器初始化一个Servlet对象时,会为这个Servlet对象创建一个ServletConfig对象。
在Servlet对象中包含了Servlet的初始化参数信息。
ServletConfig接口中定义了以下方法:
getInitParameter(String name) —— 返回匹配的初始化参数值
getInitParameterNames() —— 返回一个Enumeration对象,里面包含了所有的初始化参数名
getServletContext() —— 返回一个ServletContext对象
getServletName() —— 返回Servlet的名字,即web.xml文件中相应<servlet>元素的<servlet-name>子元素的值;如果没有为servlet配置<servlet-name>子元素,则返回Servlet类的名字
HttpServlet类继承了GenericServlet类,而GenericServlet类实现了ServletConfig接口,因此HttpServlet或GenericServlet类及子类中都可以直接调用ServletConfig接口中的方法。