Servlet技术
Servlet开发入门
Servlet接口
针对Servlet技术的开发,SUN公司提供了一系列接口和类,其中最重要的是javax.servlet.Servlet接口。Servlet就是一种实现了Servlet接口的类,它是由web容器负责创建并调用,用于接收和响应用户的请求。并把处理结果返回到客户端显示,是运行在服务端一个小程序。
Servlet的生命周期
Servlet的生命周期可分为三个阶段,具体如下:初始化阶段
运行阶段
销毁阶段
当客户端向Servlet容器发出HTTP请求要求访问Servlet时,Servlet容器首先会解析请求,检查内存中是否已经有了该Serlvet对象,如果有直接使用该Serlvet对象,如果没有就创建Servlet实例对象,然后通过调用init()方法实现Servlet的初始化工作。需要注意的是,在Servlet的整个生命周期内,它的init()方法只被调用一次。
这是Servlet生命周期中最重要的阶段,在这个阶段,Servlet容器会为这个请求创建代表HTTP请求的ServletRequest对象和代表HTTP响应的ServletResponse对象,然后将它们作为参数传递给Servlet的service()方法。在Servlet的整个生命周期内,对于Servlet的每一次访问请求,service()方法在Servlet的整个生命周期中会被调用多次。
当服务器关闭或web应用被移除出容器时,Serlvet随着web应用的销毁而销毁。在销毁Servlet之前,Servlet容器会调用Servlet的destroy()方法,以便让Servlet对象释放它所占用的资源。在Servlet的整个生命周期中,destroy()方法也只被调用一次。需要注意的是,Servlet对象一旦创建就会驻留在内存中等待客户端的访问,直到服务器关闭,或web应用被移除出容器时Servlet对象才会销毁。
HttpServlet
由于大多数Web应用都是通过HTTP协议和客户端进行交互,因此,在Servlet 接口中,提供了一个抽象类javax.servlet.http.HttpServlet。
HttpServlet是GenericServlet的子类,专门用于创建应用于HTTP协议的Servlet,处理客户端请求。通过查看HttpServlet的源代码,发现HttpServlet主要有两大功能:
(1)根据用户请求方式的不同,定义相应的doXxx()方法处理用户请求,例如,与GET请求方式对应的doGet()方法,与POST方式对应的doPost()方法。
(2)通过service()方法将HTTP请求和响应分别转为HttpServletRequest和HttpServletResponse类型的对象。
处理Get请求doGet
doGet()方法是HttpServlet类中用来处理Get请求的方法。用户通过继承HttpServlet,重写doGet()方法,实现对客户端的Get请求进行处理。要调用doGet()方法,必须在客户端的表单里指定请求的类型为Get。public void doGet(HttpServletRequest request, HttpServletResponse response)
处理Post请求doPost
doPost()是HttpServlet中用于处理Post请求的方法。如果要调用doPost()方法,必须在表单中指定Post请求。doPost()方法与doGet()方法的用法一般来说没什么区别,doGet()方法用于处理http get请求,doPost()方法用于外理http post请求。至于它们的不同,简单的说,get是通过http header来传输数据,有字数限制,而post则是通过http body来传输数据,没有字数的限制。
public void doPost(HttpServletRequest request, HttpServletResponse response)
创建Servlet,需要扩展HttpServlet类,HttpServlet类包含init()、destroy()、service()等方法,其中init()和destroy()方法是继承的。
service()方法Servlet的核心。每当一个客户请求一个HttpServlet对象,该对象的service()方法就要被调用,而且传递给这个方法一个"请求"(ServletRequest)对象和一个"响应"(ServletResponse)对象作为参数
destroy()方法在服务器停止且卸装Servlet时执行该方法。可以将Servlet作为服务器进程的一部分来关闭
GetServletConfig()方法GetServletConfig()方法返回一个ServletConfig对象,该对象用来返回初始化参数和 ServletContext。ServletContext接口提供有关servlet的环境信息
GetServletInfo()方法GetServletInfo()方法是一个可选的方法,它提供有关servlet的信息,如作者、版本、版权等
当服务器调用sevlet的Service()、doGet()和doPost()这三个方法时,均需要“请求”和“响应”对象作为参数。“请求”对象提供有关请求的信息,而“响应”对象提供了一个将响应信息返回给浏览器的一个路径。
Servlet虚拟路径的映射
在web.xml文件中,一个<servlert-mapping>元素用于映射一个Servlet的对外访问路径,该路径也称为虚拟路径。创建好的Servlet只有映射成虚拟路径,客户端才能对其进行访问。
1、Servlet的多重映射
Servlet的多重映射指的是同一个Servlet可以被映射成多个虚拟路径。它的实现方式有两种,具体如下:
(1)配置多个<servlet-mapping>元素
(2)在一个<servlet-mapping>元素下配置多个<url-pattern>子元素
2、Servlet映射路径中使用通配符
若希望某个目录下的所有路径都可以访问同一个Servlet,这时,可以在Servlet映射的路径中使用通配符“*”。通配符的格式只有两种:
(1)格式为“*.扩展名”。 例如“*.do”匹配以“.do”结尾的所有URL地址。
(2)格式为“/*”,例如“/abc/*”匹配以“/abc”开始的所有URL地址。
3、缺省Servlet
如果某个Servlet的映射路径仅仅是一个正斜线(/),那么这个Servlet就是当前Web应用的缺省Servlet。
Servlet服务器在接收到访问请求时,如果在web.xml文件中找不到匹配的<servlet-mapping>元素的URL,就会将访问请求交给缺省Servlet处理,也就是说,缺省Servlet用于处理其他Servlet都不处理的访问请求。
ServletConfig和ServletContext
ServletConfig接口
在Servlet运行期间,经常需要一些辅助信息,例如,文件使用的编码,使用Servlet程序的公司等,这些信息可以在web.xml文件中使用一个或多个<init-param>元素进行配置。当Tomcat初始化一个Servlet时,会将该Servlet的配置信息封装到一个ServletConfig对象中,通过调用init(ServletConfig cofig)方法将ServletConfig对象传递给Servlet。
ServletContext接口
当Servlet启动时,会为每个Web应用创建一个唯一的ServletContext对象代表当前Web应用,该对象不仅封装了当前Web应用的所有信息,而且实现了多个Servlet之间数据的共享。Servlet三大作用域
ServletContext针对当前项目项目任意ServletHttpSession针对会话可以存在于会话中,可以存在请求转发中
HttpServletRequest针对某次请求只存在于请求转发中
先看request作用域是否适合,如果适合直接使用,不适合再看session。
session也不适合,再考虑ServletContext。
核心API
ServletGenericServlet
HttpServlet
方法
getServletInfo()
getServletConfig()
获得ServletConfig对象
生命周期
init服务器创建小服务对象的时候回调此方法
destroy
服务器销毁小服务对象的时候回调此方法
service
客户端请求该小服务的时候回调此方法
ServletConfig 获取初始化参数
getInitParameter(String) 获取小服务上下文对象
getServletContext() 获得ServletContext对象
ServletContext 作用域-共享信息
setAttribute(String, Object) 获取物理路径
getRealPath(String) 获取上下文参数
getInitParameter(String)
ServletRequest
HttpServletRequest
getMethod()
getServletPath()
getProtocol()
获取请求头
getHeader(String)
request.getHeaderNames()
获取消息体
getParameter(String)
getParameterValues(String)
请求转发
getRequestDispatcher(String)
RequestDispatcher
forward(ServletRequest, ServletResponse)
include(ServletRequest, ServletResponse)
作用域
setAttribute(String, Object)
getAttribute(String)
读取Cookie
getCookies()
ServletResponse
HttpServletResponse
设置状态码
sendError(int)
设置响应头
setHeader(String, String)
重定向
sendRedirect(String)
添加Cookie
addCookie(Cookie)
new Cookie(String, String)
基于窗口的Cookie
例如:jsessionid
持久化的Cookie
setMaxAge(int)
getName()
getValue()
设置消息体
getOuputStream()
getWriter()
URL重写
encodeURL(String)
ServletRequestWrapper
HttpServletRequestWrapper
ServletResponseWrapper
HttpServletResponseWrapper
请求和响应
HttpServletResponse对象
发送状态码相关的方法在Servlet API中,定义了一个HttpServletResponse接口,它继承自ServletResponse,专门用来封装HTTP响应消息。
在HttpServletResponse接口中,定义了两个发送状态码的方法:
(1)setStatus(int status)方法
(2)sendError(int sc)方法
setStatus(int status)方法
该方法用于设置HTTP响应消息的状态码,并生成响应状态行。由于响应状态行中的状态描述信息直接与状态码相关,而HTTP版本由服务器确定,因此,只要通过setStatus(int status)方法设置了状态码,即可实现状态行的发送。
需要注意的是,正常情况下,Web服务器会默认产生一个状态码为200的状态行。
sendError(int sc)方法
该方法用于发送表示错误信息的状态码。在response对象中,提供了两个重载的sendError(int sc)方法,具体如下:
public void sendError(int code) throws java.io.IOException
public void sendError(int code, String message) throws java.io.IOException
第一个方法只是发送错误信息的状态码,而第二个方法除了发送状态码外,还可以增加一条用于提示说明的文本信息,该文本信息将出现在发送给客户端的正文内容中。
发送响应消息头相关的方法
发送响应消息体相关的方法
getOutputStream()方法
该方法所获取的字节输出流对象为ServletOutputStream类型。由于ServletOutputStream是OutputStream的子类,它可以直接输出字节数组中的二进制数据。因此,要想输出二进制格式的响应正文,就需要使用getOutputStream()方法。
getWriter()方法
该方法所获取的字符输出流对象为PrintWriter类型。由于PrintWriter类型的对象可以直接输出字符文本内容,因此,要想输出内容全为字符文本的网页文档,需要使用getWriter()方法。
注意:虽然response对象的getOutputStream()和getWriter()方法都可以发送响应消息体,但是,它们之间互相排斥,不可同时使用,否则会发生IllegalStateException异常
HttpServletResponse应用
中文乱码问题由于计算机中的数据都是以二进制形式存储的,因此,当传输文本时,就会发生字符和字节之间的转换。
字符与字节之间的转换是通过查码表完成的,将字符转换成字节的过程称为编码,将字节转换成字符的过程称为解码。
如果编码和解码使用的码表不一致,就会导致乱码问题
为了解决上述编码错误,在HttpServletResponse接口中,提供了一个setCharacterEncoding()方法,该方法用于设置字符的编码方式。设置字符编码使用的码表为utf-8,代码具体如下:
response.setCharacterEncoding("utf-8");
网页定时刷新并跳转
在HTTP协议中,定义了一个Refresh头字段,它可以通知浏览器在指定的时间内自动刷新并跳转到其它页面。
禁止浏览器缓存页面
缓冲页面会影响网页的部分功能
为了避免这种情况的发生,在HTTP响应消息中,需要在一个响应消息中设置三个头字段,具体如下:
Expires:0
Cache-Control:no-cache
Pragma : no-cache
请求重定向
所谓请求重定向,指的是Web服务器接受到客户端的请求后,可能由于某些条件限制,不能访问当前请求URL所指向的Web资源,而是指定了一个新的资源路径,让客户端重新发送请求。
HttpServletResponse接口中,定义了一个sendRedirect()方法,该方法用于生成302响应码和Location响应头,从而通知客户端重新访问Location响应头中指定的URL
public void sendRedirect(java.lang.String location) throws java.io.IOException
需要注意的是,参数location可以使用相对URL,Web服务器会自动将相对URL翻译成绝对URL,再生成Location头字段。
HttpServletRequest对象
获取请求行信息相关方法当访问Servlet时,会在请求消息的请求行中,包含请求方法、请求资源名,请求路径等信息,为了获取这些信息,在HttpServletRequest接口中,定义了一系列用于获取请求行信息的方法
获取请求消息头的相关方法
当请求Servlet时,需要通过请求头向服务器传递附加信息,例如,客户端可以接受的数据类型,压缩方式,语言等等。
在HttpServletRequest接口中,定义了一系列用于获取HTTP请求头字段的方法
获取请求信息行相关方法
利用Referer请求头防止“盗链”
一些站点为了吸引人气并且提高站点访问量,提供了各种软件的下载页面,但是它们本身没有这些资源,只是将下载的超链接指向其它站点上的资源。而真正提供了下载资源的站点为了防止这种“盗链”,就需要检查请求来源,只接受本站链接发送的下载请求,阻止其它站点链接的下载请求。
获取请求信息体相关方法
在HttpServletRequest 接口中,接收请求消息体时,定义了两个与输入流相关的方法,具体如下:
(1)getInputStream()方法
该方法用于获取表示实体内容的ServletInputStream对象。
(2)getReader()方法
该方法用于获取表示实体内容的BufferedReader对象,该对象会将实体内容中的字节数据按照请求消息中指定的字符集编码转换成文本字符串。
HttpServletRequest应用
获取请求参数请求参数的中文乱码问题
填写表单数据难免会输入中文,当请求参数中存在中文时,会遇到中文乱码现象。HttpServletRequest接口中,提供了一个setCharacterEncoding()方法,该方法用于设置request对象的解码方式。
需要注意的是,这种解决乱码的方式只对POST方式有效,而对GET方式无效。
获取网络连接信息
当Web服务器与客户端进行通信时,经常需要获取客户端的一些网络连接信息。为此,在ServletRequest接口中,定义了一系列用于获取客户端网络连接信息的方法。
通过Request对象传递数据
1、setAttribute()方法
该方法用于将一个对象与一个名称关联后存储进ServletRequest对象中,其完整语法定义如下:
public void setAttribute(java.lang.String?name,java.lang.Object?o);
2、getAttribute()方法
该方法用于从ServletRequest对象中返回指定名称的属性对象,其完整的语法定义如下:
public java.lang.String getAttribute (java.lang.String?name);
3、removeAttribute方法
该方法用于从ServletRequest对象中删除指定名称的属性,其完整的语法定义如下:
public void removeAttribute(java.lang.String?name);
4、getAttributeNames方法
该方法用于返回一个包含ServletRequest对象中的所有属性名的Enumeration对象,在此基础上,可以对 ServletRequest对象中的所有属性进行遍历处理。其语法定义如下:
public java.util.Enumeration getAttributeNames();
RequestDispatcher对象的应用
RequestDispatcher接口ServletRequest接口中定义了两个获取RequestDispatcher对象的方法,具体如下:
(1)getRequestDispatcher(String path)
用于返回封装了某个路径所指定资源的RequestDispatcher对象。
(2)getNamedDispatcher(String name)
用于返回封装了某个Web资源的RequestDispatcher对象,传递给该方法的参数是在Web应用程序部署好的某个Web资源名称
获取到RequestDispatcher对象后,最重要的工作就是通知其它Web资源处理当前的Servlet请求,为此,在RequestDispatcher接口中,定义了两个相关方法,具体如下:
(1)forward(ServletRequest request,ServletResponse response)
该方法用于将请求从一个Servlet传递给另外的一个Web资源。
(2)include(ServletRequest request,ServletResponse response)
该方法用于将其它的资源作为当前响应内容包含进来
请求转发
在Servlet中,如果当前Web资源不想处理它的访问请求,可以通过forward()方法将当前请求传递给其它的Web资源进行处理,这种方式称为请求转发
请求包含
请求包含指的是使用include()方法将Servlet请求转发给其它Web资源进行处理。与请求转发不同的是,在请求包含返回的响应消息中,既包含了当前Servlet的响应消息,也包含了其他Web资源所作出的响应消息。
JSP页面调用Servlet
通过表单提交调用Servlet在通过提交表单调用Servlet的时候,只需要把表单的action指向对应的Servlet即可。
通过超链接调用Servlet
当用户有输入的内容需要提交给服务器时,我们可以用表单来调用Servlet。如果在没有输入的数据内容需要提交的情况下,我们可以直接通过超链接的方式来调用Servlet,并对其传递参数。
Servlet过滤器
过滤器是小型的Web组件,它负责拦截请求和响应,以便查看、提取或以某种方式操作正在客户机和服务器之间交换的数据。Servlet过滤器应用非常广泛,有拦截的地方一般都可以用到过滤器
方法与配置
与过滤器相关的Servlet共包含3个简单的接口,分别是Filter、FilterChain及FilterConfig。要实现过滤器功能,必须先实现Filter接口。
init()方法 在容器实例化过滤器时使用,使过滤器为后面的处理操作做好准备
doFilter()方法 用于处理请求和响应,当请求与过滤器相关联Web资源时,进行调用
destroy()方法 Servlet在销毁过滤器时调用该方法
Servlets过滤器是一个Web应用组件,和Servlet类似,也需要在Web应用配置文件(即web.xml)中进行配置部署。
对于过滤器的映射配置,可以将过滤器映射到一个或多个Servlet和JSP文件中
<filter-mapping>
<filter-name>FilterName</filter-name>
<servlet-name>ServletName1</servlet-name>
</filter-mapping>
<filter-mapping>
<filter-name>FilterName</filter-name>
<servlet-name>ServletName2</servlet-name>
</filter-mapping>
注意:在web.xml中配置Servlet和Servlet过滤器,应该先声明过滤器元素,再声明Servlet元素。
Servlet监听器
主要用来对Web应用进行监听和控制,极大地增强了Web应用的事件处理能力。一般来说,Servlet监听就是指一些特殊的Servlet类,这些类可以监听Web应用的上下文信息、Servlet会话信息、Servlet请求信息。
在实际操作中,程序员需要继承或实现一些已定义好的类或接口,从而编写出自己用于监听的类。这些类对特定的信息进行监听。一旦被监听的事件发生,这些类会自动调用相应的方法去执行指定的操作。
监听Servlet上下文信息
Servlet上下文信息主要是指关于ServletContext接口的一些信息,比如ServletContext的创建和删除,Servlet属性的增加、删除和修改等。这样就可以实现对Servlet上下文信息的跟踪和记录。为了实现这样的功能,程序员需要实现ServletContextListener和ServletContextAttributeListener接口,从而编写出自己的Servlet类。
ServletContext接口的主要方法
getAttribute(String name)返回Servlet环境对象中指定的属性对象。如果该属性对象不存在,返回空值
getAttributeNames()返回一个Servlet环境对象中可用的属性名的列表
getContext(String uripath)返回一个Servlet环境对象,这个对象包括了特定URI路径的Servlets和资源,如果该路径不存在,则返回一个空值
getRealPath(String path)返回与一个符合该格式的虚拟路径相对应的真实路径的String
getResource(String uripath)返回一个URL对象,该对象反映位于给定的URL地址的Servlet环境对象已知的资源
getServerInfo()返回一个String对象,该对象至少包括Servlet引擎的名字和版本号
void log(String msg,Throwable t)写指定的信息到一个Servlet环境对象的log文件中
setAttribute(String name,Object o)给予Servlet环境对象中你所指定的对象一个名称
removeAttribute(String name)从指定的Servlet环境对象中删除一个属性
在使用这个监听器之前还需要对Web模块中的web.xml配置文件进行配置
<listener>
<listener-class>servlets.MyServletContextListener</listener-class>
</listener>
然后我们就可以编写一个JSP程序testListener.jsp来操作ServletContext的属性,看监听器程序做出什么反应。
监听HTTP会话信息
HTTP会话信息指的是Session对象的创建和销毁、会话中属性的设置请求、会话的状态和会话的绑定信息等。通过对HTTP会话信息的监听,可以进行一些很有用的操作,比如,统计当前会话的数目、设置某个对话的属性、了解某个对话的状态等。
与ServletContext监听的实现方法类似,对HTTP会话的监听也是通过实现特定的接口来完成的。监听HTTP会话信息需要使用到三个接口类:HttpSessionListener、HttpSessionActivationListener和HttpSessionAttributeListener接口。
接口常用方法
sessionCreated(HttpSessionEvent arg0)方法进行Http会话创建的监听,如果Http会话被创建将调用该方法
sessionDestroyed(HttpSessionEvent arg0)方法对Http会话销毁进行监听,如果某个Http会话被释放将调用该方法
sessionDidActivate(HttpSessionEvent arg0)方法对Http会话处于active情况进行监听
sessionWillPassivate(HttpSessionEvent arg0)方法对Http会话处于passivate情况进行监听
attributeAdded(HttpSessionBindingEvent arg0)方法对Http会话中属性添加进行监听
attributeReplaced(HttpSessionBindingEvent arg0)方法对Http会话中属性修改进行监听
attributeRemoved(HttpSessionBindingEvent arg0)方法对Http会话中属性删除进行监听
对客户端请求进行监听
客户端请求信息是指请求对象的创建、销毁以及其属性的添加、更改和删除。一旦可以对客户端发向服务器的请求进行监听,就可以对它们进行识别,然后统一处理。对客户端请求信息的监听的实现方法与上面两种类似,通过实现ServletRequestListener和ServletRequestAttributeListener接口来完成。
接口只要方法
ServletRequestListener()方法监听客户端请求的创建和销毁
attributeAdded(HttpSessionBindingEvent arg0)方法对Http会话中属性添加进行监听
attributeReplaced(HttpSessionBindingEvent arg0)方法对Http会话中属性修改进行监听
attributeRemoved(HttpSessionBindingEvent arg0)方法对Http会话中属性删除进行监听
配置
注解@WebServlet
value
urlPatterns
loadOnStartup
web.xml
<servlet> -> <servlet-name> / <servlet-class> / <load-on-startup>
<servlet-mapping> -> <servlet-name> / <url-pattern>
在web.xml中如下配置servlet。
<servlet>
<!--给自己的servlet类器一个名字-->
<servlet-name>helloServlet</servlet-name>
<!--要访问该类的全类名-->
<servlet-class>cn .itcast .demo. servlet .HelloServlet< / servlet-class>
</servlet>
<servlet -mapping>
<servlet-name>helloServlet</servlet-name>
<!--serlvet 访问地址-->
<url-pattern>/ hello</url-pattern>
</servlet -mapping>
最能让人感到快乐的事,莫过于经过一番努力后,所有东西正慢慢变成你想要的样子!