Servlet基础上
1 什么是Servlet
Servlet是JavaWeb应用中最核心的组件,属于动态资源。本质上Servlet是一个实现了javax.servlet.Servlet接口的Java类,且Servlet类运行在Servlet容器中,其对象由Servlet容器创建,通过该对象,可以访问Servelt容器提供的其他资源。
2 Servlet作用
Servlet容器接收客户端请求,并交给Servlet处理。其作用如下:
Ø 动态生成HTML文档;
Ø 将请求转发给同一个Web应用中其他Servlet组件;
Ø 将请求转发给其他Web应用中的Servlet组件;
Ø 读取客户端的Cookie,以及向客户端写入Cookie;
Ø 访问其他服务器资源(如数据库)。
3 Servlet特点
l Servlet类是由程序员编写,对象由Servlet容器创建,且Servlet容器调用相应方法。
l 一个Web应用中可以存在很多Servlet类,但每个Servlet类只有一个对象(即Servlet类单例)。servlet-name.
l Servlet类线程不安全,效率较高。
4 第一个Servlet程序
step01- 编写一个Java类实现Servlet接口
public class FirstServlet implements Servlet{
@Override
public void destroy() {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void init(ServletConfig arg0) throws ServletException {
}
@Override
public void service(ServletRequest arg0, ServletResponse arg1)
throws ServletException, IOException {
PrintWriter out = arg1.getWriter();
out.println("my first Servelt program");
}
}
step02- 导入servlet.jar包
> set classpath=%classpath%;c:\tomcat7\lib\servlet-api.jar
step03- 编译带包的类
> javac -d . FirstServlet.java
step04- 在webapps中创建web应用
hello
WEB-INF
classes
FirstServlet全路径名(包名+类名)
-
web.xml
且在WEB-INF中存放编译的class文件和web.xml文件。
step05- 配置web.xml文件中
<servlet>
<servlet-name>firstServlet</servlet-name>
<servlet-class>com.hao.demo01.FirstServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>firstServlet</servlet-name>
<url-pattern>/first</url-pattern>
</servlet-mapping>
Servlet执行流程分析
1)根据URL:http://localhost:8080,解析出主机及web服务器。
2)根据/hello/first,解析出上下文路径及访问资源
3)根据/first,查找web.xml中对应的<servlet-name>, 根据<servlet-name>再查找<servlet-class>值
注意:tomcat加载web应用时,会先把web.xml文件读入到内存中,当需要参考web.xml文件时,实际只需要从内存中读取相关数据就行,无需再到文件系统中读取web.xml。
4)根据包名和类名,反射创建FirstServelt对象,调用init方法
Servlet servlet = (Servlet)servletCache.get(firstServlet);
if(servlet == null){
//Servle对象一创建,就初始化
servlet = (Servlet)Class.forName(com.hao.demo01.FirstServlet).newInstance();
servlet.init();//Servlet对象一旦创建,即初始化
servletCache.put(firstServlet, servlet);
}
5)根据客户请求(request),调用service方法,并根据response对象,将” myfirst servlet program”发送给浏览器。
servlet.service(res, resp)
5用MyEclipse开发第一个Servlet
在MyEclipse中创建web project。
src包中创建一个java类实现Servlet接口
webroot\WEB-INF\web.xml做servlet映射
启动tomcat,将工程发布到tomcat服务器
浏览器访问。
6Servlet细节
Ø 关于URL映射配置
Ø 关于Servlet进行URL映射
Servlet规范之所以规定对Servlet进行URL映射,有两点原因?
a.可以为一个Servlet映射多个URL。
http://localhost:8080/myapp/login.do http://localhost:8080/myapp/loginout.do http://localhost:8080/myapp/checkout.do 使用以*问,全部都有ActionServlet处理。 注意:* 为通配符。映射Servlet路径时,可以使用 /* 或 *.扩展名 两种形式。两者不能同时使用,/*具有较高的优先级。(/servlet/*也可以,但不可以/*.do或*.*) 一个<servlet>还可以对应多个<servlet-mapping>元素 |
b.简化Servlet的URL,且可以向客户端隐藏Web应用实现细节
在URL中暴露Servlet的完整类名,复杂,不容易理解和记忆。对Servlet进行URL映射,可以提供一个简洁易懂的URL。
Ø load-on-startup元素
<servlet>元素下可以配置<load-on-startup>子元素。
配置方式如下:
<load-on-startup>1</load-on-startup>
用于指定Servlet容器启动Web应用时,加载各个Servlet的次序。如果值为0或正数,Servlet容器先加载数值小的Servlet,再依次加载数值大的Servlet;如果值为负数或没有设定,Servlet容器将在客户端首次访问Servlet时加载它
Ø tomcat\conf\web.xml
服务器下所有web应用中的web.xml都会自动继承该文件中所有的配置信息。
http:localhost:8080/hello/a.html
上面的URL资源名(a.html)在web.xml文件中并没有配置,此时访问时,先访问缺省的Servlet,在tomcat\conf\web.xml文件中配置了一个缺省的DefaultServlet。DefaultServlet帮我们去web应用下读取a.html,并响应给浏览器。如果没有,发送404。也就是说,我们通过IE访问服务器访问的都是Servlet。
<servlet>//优先级最低,如果请求无人处理或不存在,则它来处 <servlet-name>default</servlet-name>//理,否则显示404 <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value>false</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
<servlet> <servlet-name>jsp</servlet-name> <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> <init-param> <param-name>fork</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>xpoweredBy</param-name> <param-value>false</param-value> </init-param> <load-on-startup>3</load-on-startup> </servlet>
<servlet-mapping> <servlet-name>default</servlet-name> //以下匹配所有URL,即访问URL没有匹配页面,则执行//DefaultServlet <url-pattern>/</url-pattern> </servlet-mapping> //以下表示任何URL后缀为JSP访问时,都是执行名称为jsp的Servlet,即JspServlet <servlet-mapping> <servlet-name>jsp</servlet-name> <url-pattern>*.jsp</url-pattern> <url-pattern>*.jspx</url-pattern> </servlet-mapping>
<session-config>//默认session超时为30分钟 <session-timeout>30</session-timeout> </session-config> //定义了很多MIME类型 <mime-mapping> <extension>bmp</extension> <mime-type>image/bmp</mime-type> </mime-mapping> <mime-mapping> <extension>htm</extension> <mime-type>text/html</mime-type> </mime-mapping> //在Web应用的web.xml中如果没有对下面标签进行覆盖,默认主页为index.html, index.htm, index.jsp <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> </welcome-file-list> |
7Servlet相关接口和类的关系及详细分析
a)Servlet API
i.ServletAPI主要由两个包组成:javax.servlet和javax.servlet.http。在javax.servlet包中定义了Servlet接口及相关的通用接口和类;在javax.servlet.http包中主要定义了与HTTP协议相关的类与接口。
javax.servlet包中的接口和类:
ServletDispatcher接口
ServletContext接口
ServletConfig接口
Servlet接口
ServletRequest接口
ServletResponse接口
GenericServlet抽象类
javax.servlet.http包中的接口和类:
HttpServlet抽象类
HttpServletRequest接口
HttpServletResponse接口
ii.ServleltAPI中主要的接口与类关系
b)Servlet接口(查看源代码)
Servlet接口是Servlet API的核心,所有Servlet类都必须实现该接口。
Servlet接口定义了5个方法:
以下三个方法由Servlet容器在Servlet生命周期不同阶段调用相应方法。
1-init(ServletConfig config):负责初始化Servlet对象。容器在创建好Servlet对象后,就调用该方法。
2-service(ServletRequestrequest, ServletResponse response):负责响应客户的请求,为客户提供相应服务。当容器接收到客户端要求访问特定Servlet对象的请求时,就调用该Servlet对象的service方法
3-destroy():负责释放Servlet对象占用的资源。Servlet对象生命周期结束前,容器调用该方法。
以下两个方法返回Servlet相关信息的方法。Web应用中的程序代码可以访问Servlet这两个方法,获得Servlet的配置信息及其他相关信息。
4-getServletConfig():返回一个ServletConfig对象,该对象中包含Servlet初始化参数信息。
5-getServletInfo():返回一个字符串,该字符串中包含了Servlet的创建者,版本和版权等信息。
c)GenericServlet抽象类(查看源代码)
GenericServlet抽象类为Servlet接口提供了通用实现,它与任何网络应用层协议无关。GenericServlet实现了Servlet接口,ServletConfig接口,Serializable接口。
//GenericServlet实现了ServletConfig中所有的方法,其子类可以直接调用这些方法 publicabstractclassGenericServletimplements Servlet, ServletConfig, java.io.Serializable { privatestaticfinallongserialVersionUID = 1L; privatetransient ServletConfig config; public GenericServlet() {}
//具体子类可以覆盖该方法,在销毁Servlet对象前释放所占资源如关闭IO流对象,数据库连接 @Override publicvoid destroy() {}
@Override public String getInitParameter(String name) { return getServletConfig().getInitParameter(name); }
@Override public Enumeration<String> getInitParameterNames() { return getServletConfig().getInitParameterNames(); } @Override public ServletConfig getServletConfig() { returnconfig; }
@Override public ServletContext getServletContext() { return getServletConfig().getServletContext(); }
@Override public String getServletInfo() { return""; }
@Override publicvoid init(ServletConfig config) throws ServletException { this.config = config; this.init(); }
publicvoid init() throws ServletException {}
publicvoid log(String msg) { getServletContext().log(getServletName() + ": " + msg); }
publicvoid log(String message, Throwable t) { getServletContext().log(getServletName() + ": " + message, t); }
//子类必须实现该方法,为特定客户请求提供具体服务。 @Override publicabstractvoid service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
@Override public String getServletName() { returnconfig.getServletName(); } } GenericServlet实现了Servlet接口和ServletConfig接口。主要身份是Servlet,运用了装饰设计模式,且为自己附加了ServletConfig装饰身份。具体实现中,GenericServlet类包装了一个ServletConfig接口的实例,通过该实例来实现ServletConfig接口中的方法。 实现ServletConfig接口,且在类中创建ServletConfig对象。返回各个方法。 |
d)HttpServlet抽象类(查看源代码)
HttpServlet类是GenericServlet类的子类。HttpServlet类为Servlet接口提供了与HTTP协议相关的通用实现,即HttpServlet对象适合运行在与客户端采用HTTP协议通信的Servlet容器或者Web服务器中。
开发JavaWeb应用时,自定义的Servlet类一般都扩展HttpServlet类。
HTTP协议把客户请求分p为GET,POST, PUT, DELETE等多种方式。HttpServlet类针对每一种请求方式都提供了相应的服务方法,如doGet,doPost, doPut, doDelete等方法。
publicabstractclassHttpServletextends GenericServlet { privatestaticfinallongserialVersionUID = 1L; privatestaticfinal String METHOD_GET = "GET"; privatestaticfinal String METHOD_POST = "POST";
public HttpServlet() {}
protectedvoid doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String protocol = req.getProtocol(); String msg = lStrings.getString("http.method_get_not_supported"); if (protocol.endsWith("1.1")) { resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); } else { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); } }
protectedvoid doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String protocol = req.getProtocol(); String msg = lStrings.getString("http.method_post_not_supported"); if (protocol.endsWith("1.1")) { resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); } else { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); } } protectedvoid service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
if (method.equals(METHOD_GET)) { long lastModified = getLastModified(req); if (lastModified == -1) { doGet(req, resp); } else { long ifModifiedSince; try { ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); } catch (IllegalArgumentException iae) { ifModifiedSince = -1; } if (ifModifiedSince < (lastModified / 1000 * 1000)) { maybeSetLastModified(resp, lastModified); doGet(req, resp); } else { resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } } } elseif (method.equals(METHOD_HEAD)) { long lastModified = getLastModified(req); maybeSetLastModified(resp, lastModified); doHead(req, resp); } elseif (method.equals(METHOD_POST)) { doPost(req, resp);
} elseif (method.equals(METHOD_PUT)) { doPut(req, resp);
} elseif (method.equals(METHOD_DELETE)) { doDelete(req, resp);
} elseif (method.equals(METHOD_OPTIONS)) { doOptions(req,resp);
} elseif (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); } } @Override publicvoid service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request; HttpServletResponse response;
try { request = (HttpServletRequest) req; response = (HttpServletResponse) res; } catch (ClassCastException e) { thrownew ServletException("non-HTTP request or response"); } service(request, response); } } |
实际使用中,HttpServlet具体子类,会针对客户端的特定请求方式,来重写HttpServlet父类中对应的doXxx()方法。为了doXxx方法能被Servlet容器访问,访问修饰符应该为public。
客户端按照GET,POST方式请求访问HelloServlet,且两种方式下HelloServlet提供同样服务,则在HelloServlet类中如下方式实现。
public class HelloServlet extends HttpServlet{ @Override protectedvoid doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //提供具体的实现代码 }
@Override protectedvoid doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } } |
以上类与接口关系
e)ServletRequest接口
Servlet接口的service(ServletRequestreq, ServletResponse resp),含有ServletRequest类型。表示客户端的请求。
当Servlet容器接收到客户端要求访问特定Servlet请求时,容器会先解析客户端的原始请求数据,把它包装成一个ServletRequest对象,当容器调用Servlet对象的service()方法时,可以把ServletRequest对象作为参数传给service()方法。
ServletRequest接口提供了访问客户端请求数据的方法。(查看API)
1-getContentLength:返回请求正文长度,如果正文长度未知,则返回-1 2-getContentType:获得请求正文的MIME类型。如果请求正文未知,返回null 3-getInputStream: 返回用于读取请求正文的输入流 4-getLocalAddr:返回服务器IP地址 5-getLocalName:返回服务器端主机名 6-getLocalPort:返回服务器端的HTTP端口号 7-getParameter(String name):根据请求参数名,返回来自客户请求中匹配的请求参数值。 8-getProtocal: 返回客户端与服务器端通信所有协议名称及版本号 9-getReader:返回用于读取字符串形式的请求正文的BufferedReader对象。 10-getRemoteAddr:返回客户端IP地址 11-getRemoteHost:返回客户端主机名 12-getRemotePort:返回客户端HTTP端口号 13-setCharacterEncoding 请求范围内存取共享数据 13-setAttribute(String name, Object obj):请求范围内保存一个属性,参数name表示属性名,参数obj表示属性值 14-getAttribute(String name):根据name参数给定的属性名,返回请求范围内匹配的属性值. 15-removeAttribute(String name):从请求范围内删除一个属性。 |
f)HttpServletRequest接口
HttpServletRequest接口是ServletRequest接口的子接口。HttpServlet类重载service方法及doGet,doPost都有一个该类型参数。
HttpServletRequest接口提供了用于读取HTTP请求中相关信息的方法
以http://localhost:8080/helloapp/info?name=jack为例 1-getContextPath: 返回客户端所请求访问的web应用的URL入口。即/helloapp 2-getCookies():返回HTTP请求中所有Cookie 3-getHeader(String name):返回HTTP请求头部的特定项 4-getHeaderNames():返回一个Enumeration对象,包含了HTTP请求头部所有项目名 5-getMethod:返回HTTP请求方式 6-getRequestURI():返回HTTP请求的头部的第一行中的URI。 /helloapp/info?name=jack 7-getQueryString():返回HTTP请求中的查询字符串。即name=jack |
案例:使用以上方法
g)ServletResponse接口
Servlet接口的service(ServletRequestreq, ServletResponse resp),含有ServletResponse类型。Servlet通过ServletResponse对象生成响应结果(主要生成HTTP响应结果的正文部分)。
Servlet容器接收到客户端要求访问特定Servlet请求时,容器会创建一个ServletResponse对象,并把它作为参数传给Servlet的service方法。
ServletResponse接口定义了一系列与生成响应结果相关的方法。
1-setCharacterEncoding(String charset): 设置响应正文的字符编码。默认响应正文字符编码为ISO-8859-1 2-setContentLength(int len): 设置响应正文的长度 3-setContentType(String type):设置响应正文的MIME类型 4-getCharacterEncoding():返回响应正文的字符编码 5-getContentType():返回响应正文的MIME类型 6-setBufferSize(int size):设置用于存放响应正文数据的缓冲区大小 7-getBufferSize():获得用于存放响应正文数据的缓冲区大小 8-reset():清空缓冲区内的正文数据,并且清空响应状态代码及响应头 9-resetBuffer():仅仅清空缓冲区内的响应正文数据,不清空响应状态代码及响应头 10-flushBuffer():强制性把缓冲区内的响应正文数据发送到客户端 11-isCommitted():返回一个boolean类型的值。true表示缓冲区内的数据已经提交给客户。即数据已经发送到客户端。 12-getOutputStream():返回一个ServletOutputStream对象,Servlet用它输出二进制的正文数据 13-getWriter():返回一个PrintWriter对象,servlet用它输出字符串形式的正文数据。 |
注意:
1-提高输出数据效率,ServletOutputStream和PrintWriter先把数据写到缓冲区内。tomcat在调用完Servlet的service方法后,会关闭以上两个对象,确保Servlet输出的所有数据被提交给客户。
2-ServletResponse响应正文默认MIME类型为text/plain(纯文本类型)。HttpServletResponse响应正文默认的MIME类型为text/html(html文档类型)。
3-设置响应正文的MIME类型和字符编码时,必须先调用setContentType()和setCharacterEncoding方法,然后再调用ServletResponse的getOutputStream或getWriter方法,或提交缓冲区内的正文数据。满足这样顺序,设置才能生效。
h)HttpServletResponse接口
HttpServletResponse接口是ServletResponse接口的子接口。HttpServlet类重载service方法及doGet,doPost都有一个该类型参数。
HttpServletResponse接口提供了与HTTP协议相关的方法。Servlet可通过这些方法设置HTTP响应头或向客户端写Cookie。
1-addHeader(String name, String value):向HTTP响应头加入一项内容 2-sendError(int sc):向客户端发送一个代表特定错误的HTTP响应状态代码 3-sendError(int sc, String msg):向客户端发送一个代表特定错误的HTTP响应状态代码,并且发送具体错误信息 4-setHeader(String name, String value):设置HTTP响应头中一项内容。如果响应头已经存在这项内容,原设置将被覆盖 5-setStatus(int sc):设置HTTP响应的状态代码 6-addCookie(Cookie cookie):向HTTP响应中加入一个Cookie。 |
案例演示:
注意:设置HTTP响应正文的MIME类型及字符编码三种方式
1 response.setContentType(“text/html;charset=GB2312”);
2 response.setContentType(“text/html”);
response.setContentType(“GB2312”);或setCharacterEncoding(“GBK”);
3 response.setHeader(“Content-type”,“text/html;charset=GB2312”);
i)ServletConfig接口
Servlet接口的init(ServletConfigconfig)方法含有ServletConfig类型的参数。
Servlet容器初始化一个Servlet对象时,会为该Servlet对象创建一个ServletConfig对象。Servlet容器在调用Servlet对象的init(ServletConfig config)方法时,会把ServletConfig对象作为参数传给Servlet对象。init(ServletConfig config)方法使得当前Servlet对象与ServletConfig对象之间建立关联关系。
ServletConfig对象中包含了Servlet初始化参数信息,此外该对象与当前Web应用的ServletContext对象关联。1、获得Servlet初始化参数信息;2、得到ServletContext对象
ServletConfig接口定义的方法
1-getInitParameter(String name)根据给定的初始化参数名,返回匹配的初始化参数值 2-getInitParameterNames():返回一个Enumeration对象,里面包含了所有的初始化参数名。 3-getServletContext():返回一个ServletContext对象。 4-getServletName():返回Servlet的名字,即web.xml文件中相应的<servlet-name>的值。如果没有配置,则返回Servlet类的名字 |
在<servlet>中,通过<init-param>元素设置初始化参数。<param-name>设置参数名,<param-value>设置参数值
HttpServlet类继承GenericServlet类,GenericServlet类实现了ServletConfig接口,因此在HttpServlet或GenericServlet类及其子类中可以直接调用ServletConfig方法。
j)ServletContext接口
ServletContext是Servlet与Servlet容器之间直接通信的接口。
ServletContext在容器在启动一个Web应用时,会为它创建一个ServletContext对象。
每个Web应用有且仅有一个ServletContext对象,同一个Web应用中的所有Servlet对象都共享该对象。可以通过该对象访问容器中的各种资源。
ServletContext接口提供以下几种类型方法
在web应用范围内存取共享数据的方法: 1-setAttribute(String name, Object object):把一个Java对象与一个属性名绑定,并把它存入到ServletContext中。name为属性名,object表示共享数据 2-getAttribute(String name):根据属性名,返回一个Object类型的对象。不存在,返回null。 3-getAttributeNames():返回一个Enumeration对象,该对象包含了所有存放在ServletContext中的属性名。 4-removeAttribute(String name): 根据参数指定的属性名,从ServletContext中删除匹配的属性。 访问当前Web应用的资源 1-getContextPath():返回当前Web应用的URL入口 /hello 2-getInitParameter(String name):根据给定的参数名,返回Web应用范围内的匹配的初始化参数值。在web.xml中,直接在<web-app>根元素下定义的<context-param>元素表示应用范围内的初始化参数。 3-getInitParameterNames():返回一个Enumeration对象,包含了Web应用范围内的所有初始化参数名 4-getServletContextName():返回Web应用的名字。即在web.xml中<display-name>元素的值。 5-getRequestDispatcher(String path): 返回一个用于向其他Web组件转发请求的RequestDispatcher对象 访问Servlet容器中其他Web应用 1-getContext(String uripath):根据参数指定URI,返回当前Servlet容器中其他Web应用的ServletContext对象 访问Servlet容器的相关信息 1-getMajorVersion():返回Servlet容器支持的Java Servlet API的主版本号。 2-getMinorVersion():返回Servlet容器支持的Java Servlet API的次版本号 3-getServletInfo():返回Servlet容器的名字和版本。 访问服务器端的文件系统资源 1-getRealPath(String path):根据参数指定的虚拟路径,返回文件系统中一个资源的真实的路径。 path=/WEB-INF/web.xml /表示当前应用。 2-getResource(String path):返回一个映射到参数指定的路径的URI 3-getResourceAsStream(String path): 返回一个用于读取参数指定的文件的输入流。比如path=”/WEB-INF/web.xml” /表示当前web应用入口,对象可以读取指定文件的数据。 4-getMimeType(String file):返回参数指定的文件的MIME类型 输出日志 1-log(String msg):向Servlet日志文件中写日志 2-log(String message, Throwable throwable):向Servlet的日志文件中写错误日志,以及异常的堆栈信息 |
在HttpServlet,GenericServlet类及其子类中可以直接调用getServletContext()方法得到当前Web应用的ServletContext对象。
案例:以流的形式获取资源的方法总结
在实际操作中,经常以IO流的方式读取文件系统中的文件信息。除了IO流,还有其他方式在JavaSE或JavaWeb中可以使用。
以流的形式读取文件系统中的资源,最主要的是指定的路径能被读取对象找到。
javaSE
//1- 直接使用IO流对象读取即可。
//2- 通过getResourceAsStream方法 以下使用的都是相对路径
// 路径 /xxx文件。 表示当前相对位置bin目录。
//InputStream is1 = Test.class.getResourceAsStream("/web.xml");
//当前目录 与当前类对应的.class所在的目录相同。
//InputStream is11 = Test.class.getResourceAsStream("web.xml");
//3- 不能以/开头, 如下所示, 当前目录就是bin目录。
InputStream is2 = Test.class.getClassLoader().getResourceAsStream("web.xml");
//相对的目录时classes。
//InputStream is1 = Test.class.getResourceAsStream("/web.xml");
//当前目录为与当前类的.class文件所在目录相同。
InputStream is2 = Test.class.getResourceAsStream("web.xml");
//相对目录是classes
InputStream is3 = Test.class.getClassLoader().getResourceAsStream("web.xml");
//相对目录为当前Web应用的入口。
InputStream is4 = this.getServletContext().getResourceAsStream("/WEB-INF/classes/web.xml");
JavaWe应用的生命周期
JavaWeb应用的生命周期是由Servlet容器控制。包括启动阶段,运行时阶段,终止阶段。
a.启动阶段
Servlet容器启动JavaWeb应用时,完成以下任务
(1) 把web.xml文件中数据加载到内存中
(2)为JavaWeb应用创建一个ServletContext对象
(3)对所有的Filter进行初始化(以后讲解)
(4)对需要在Web应用启动时就被初始化的Servlet进行初始化。<load-on-startup>配置
b.运行时阶段
JavaWeb应用最主要的生命阶段。随时响应客户端的特定请求,提供相应服务。如果请求的Servlet对象还不存在,Servlet容器会先初始化Servlet,然后再调用它的service服务方法。
c.终止阶段
Servlet容器在终止JavaWeb应用时,完成以下任务:
(a)销毁JavaWeb应用中所有处于运行时状态的Servlet。
(b)销毁JavaWeb应用中所有处于运行时状态的Filter。
(c)销毁所有与JavaWeb应用相关的对象。如ServletContext对象,且释放Web应用所占用的相关资源。
Web应用随着Servlet容器启动而启动,运行而运行,终止而终止。Tomcat作为Servlet容器的具体实现,提供了一个管理平台,用户可以手动管理单个Web应用的生命周期。
演示:用Tomcat管理平台管理Web应用的生命周期
步骤:配置tomcat-users.xml,启动tomcat,访问进入管理平台。
注意:<Context>元素有一个reloadable属性,如果为true,Tomcat在运行时会监视Web应用中WEN-INF/classes,WEB-INF/lib目录下类文件的改动以及监视Web应用的WEB-INF/web.xml文件的改动。如果监测到类文件或web.xml文件被更新,tomcat则会重新启动Web应用。该属性默认为false。一般在Web应用的开发和调试阶段,为了方便Web应用的调试,reloadable设置true。Web应用正式发布阶段,设置false,降低tomcat运行负荷,提高Tomcat的运行性能。
2Servlet生命周期,(面试题!)
JavaWeb应用的生命周期由Servlet容器控制,而Servlet作为JavaWeb应用的最核心组件,其生命周期也由Servlet容器控制。
Servlet生命周期分为三个阶段:初始化阶段,运行时阶段,销毁阶段。在Servlet接口中定义了三个方法init, service, destroy,分别在Servlet不同阶段被Servlet容器调用。
a.初始化阶段
(1)Servlet容器加载Servlet类,把它的.class文件中的数据读入到内存中。
(2)Servlet容器创建ServletConfig对象。建立ServletConfig对象与当前Web应用的ServletContext对象关联。
(3)Servlet容器创建Servlet对象
(4)Servlet容器调用Servlet对象的init(ServletConfig config)方法。建立Servlet对象与ServletConfig对象的关联关系
以下情况下,Servlet进入初始化阶段
Ø 当前Web应用处于运行时阶段,特定Servlet被客户端首次请求访问。多数Servlet都会在这种情况下被Servlet容器初始化。
Ø 如果在web.xml文件中为一个servlet设置了<load-on-startup>元素,那么当Servlet容器启动Servlet所属的Web应用时,就会初始化这个Servlet。
Ø 当Web应用被重新启动时,Web应用中的所有Servlet都会在特定时刻重新初始化。
b.运行时阶段
Servlet生命周期最重要的阶段。此时Servlet可以随时响应客户端请求。当Servlet容器接收到要求访问特定Servlet的客户请求时,Servlet容器会创建针对这个请求的ServletRequest对象和ServletResponse对象,然后调用相应Servlet对象的service()方法。service()方法从ServletRequest对象中获得客户请求信息并处理该请求,再通过ServletResponse对象生成响应结果。当Servlet容器把Servlet生成的响应结果发送给客户,Servlet容器就会销毁ServletRequest对象和ServletResponse对象。
c.销毁阶段
当Web应用被终止时,Servlet容器会先调用Web应用中所有Servlet对象的destroy()方法,然后再销毁这些Servlet对象。容器还会销毁与Servlet对象关联的ServletConfig对象。
一般在destroy()方法中,可以释放Servlet占用的资源,比如关闭文件输入流和输出流,关闭与数据库的连接等。
演示Servlet生命周期
在Servlet生命周期中,Servlet初始化,销毁只发生一次,因此init()和destroy()方法只会被Servlet容器调用一次,而service()方法可能会被Servlet容器调用多次,取决于客户端请求访问Servlet次数。
3ServletContext与Web应用范围共享
ServletContext对象与Web应用的生命周期相同,且ServletContext对象可以被Web应用中的所有Web组件共享,因此可以使用ServletContext对象实现Web应用范围内的共享数据。
ServletContext接口中用于存取共享数据的方法:
Ø setAttribute(String name, Object object):向WEB应用范围内存入共享数据。
共享数据存放在object,且该对象生命周期依附于ServletContext对象的生命周期,且Web组件可以通过ServletContext对象访问。
Ø removeAttribute(String name):根据参数给定属性名,从Web应用范围内删除匹配的共享数据。
Ø getAttribute(String name):根据参数给定的属性名,返回Web应用范围内匹配的共享数据
案例:web应用范围内存放共享数据
4ServletContextListener监听器
ServletContextListener接口,能够监听ServletContext对象的生命周期,实际也是监听Web应用的生命周期
当Servlet容器启动或终止Web应用时,会触发ServletContextEvent事件,该事件由ServletContextListener处理。
ServletContextListener接口定义了处理ServletContextEvent事件的两个方法:
Ø contextInitialized(ServletContextEvent sce):Servlet容器启动Web应用时调用该方法。该方法调用完后,容器再对Filter初始化,且对Web启动时就需要被初始化的Servlet进行初始化。
Ø contextDestroyed(ServletContextEvent sce): 当Servlet容器终止Web应用时,调用该方法。在调用该方法之前,容器会先销毁所有的Servlet和Filter。
每次,如果重新启动Web应用,计数器都会重新从1开始统计访问次数。实际应用中,往往需要统计自Web应用发布后,网页被客户端访问的次数。这需要Web应用每次被终止时,计数器数值被永久存储在一个文件或数据库中,等到Web重新启动时,先从文件或数据库中读取计数器的值,再继续计数。
案例演示:
可以看出Web应用启动时,Servlet容器先调用MyServletContextListener的contextInitialized方法,再创建,初始化Servlet对象;Web应用终止时,Servlet容器先调用Servlet的destroy方法,再调用MyServletContextListener的contextDestroyed方法。由此可知,Web应用的生命周期中,ServletContext对象最早创建,最晚销毁。
5Servlet服务方法抛出异常
Servlet接口的service方法完整定义如下:
publicvoid service(ServletRequest req, ServletResponse res) throws ServletException, IOException; |
该方法声明抛出两个异常:
Ø ServletException:表示当Servlet进行常规操作时出现的异常
Ø IOException:表示当Servlet进行IO操作时出现的异常
Ø UnavailableException:ServletException子类,表示无法访问当前Servlet异常。如果Servlet由于一些系统级别原因(内存不足或无法访问第三方服务器(DB服务器))不能响应客户请求,就抛出该异常。
Servlet的service()方法抛出的异常由Servlet容器捕获,Servlet容器在捕获到异常后,会向客户端发送相应错误信息。
6 防止页面被客户端缓存 (***重要***)
客户端缓存:浏览器为了能快速向用户展示请求页面,会将服务器端的网页存放到客户端缓存中。多次请求访问服务器端同一网页,只需从缓存中获取该网页即可。
浏览器缓存技术适用于保存服务器端的静态网页,以及不含敏感数据的网页。下面两种情形,服务器不希望网页被客户端缓存。
Ø 网页包含随时被更新的动态内容。此时如果浏览器读取缓存网页,可能展示的是过期网页。
Ø 网页中含有敏感数据。比如银行账号信息或电子邮件内容,如果浏览器把网页保存在本地缓存中,可能被其他未授权的用户访问。
服务器端禁止浏览器缓存网页,可通过HttpServletResponse对象设置特定HTTP响应头实现。
response.addHeader(“Pragma”, “no-cache”); response.setHeader(“Cache-Control”, “no-cache”); response.setHeader(“Expires”, “0”); |
注意:
Ø “Pragma”适用于采用HTTP1.0浏览器。
Ø “Cache-Control” 在HTTP1.1中用来决定客户端是否可以缓存网页,如果取值no-cache,客户端不会把Servlet生成的网页保存在本地缓存。
Ø “Expires” HTTP1.0和HTTP1.1都支持,因此所有浏览器都识别该选项。Expires用于设置网页过期时间,如果为0,表示立即过期。用户每次重复请求访问该网页,浏览器每次都从服务器端获取最新的网页。