JavaWeb学习笔记(三)之Servlet

时间:2021-07-02 13:08:20

Servlet基础上

什么是Servlet

ServletJavaWeb应用中最核心的组件,属于动态资源。本质上Servlet是一个实现了javax.servlet.Servlet接口的JavaServlet类运行在Servlet容器中,其对象由Servlet容器创建通过该对象,可以访问Servelt容器提供的其他资源。

Servlet作用

Servlet容器接收客户端请求,并交给Servlet处理。其作用如下:

Ø  动态生成HTML文档;

Ø  将请求转发给同一个Web应用中其他Servlet组件;

Ø  将请求转发给其他Web应用中的Servlet组件;

Ø  读取客户端的Cookie,以及向客户端写入Cookie

Ø  访问其他服务器资源(如数据库)。

Servlet特点

l  Servlet类是由程序员编写,对象由Servlet容器创建,且Servlet容器调用相应方法。

l  一个Web应用中可以存在很多Servlet类,但每个Servlet类只有一个对象(Servlet类单例)。servlet-name.

l  Servlet类线程不安全,效率较高。

第一个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全路径名(包名+类名)

  1.                     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> 
               step06-  打开浏览器,访问http://localhost:8080/hello/first 

 

      Servlet执行流程分析

1)根据URLhttp://localhost:8080,解析出主机及web服务器。

2)根据/hello/first,解析出上下文路径及访问资源

3)根据/first查找web.xml中对应的<servlet-name>, 根据<servlet-name>再查找<servlet-class>

注意:tomcat加载web应用时,会先把web.xml文件读入到内存中,当需要参考web.xml文件时,实际只需要从内存中读取相关数据就行,无需再到文件系统中读取web.xml

JavaWeb学习笔记(三)之Servlet

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)

5MyEclipse开发第一个Servlet

MyEclipse中创建web project

src包中创建一个java类实现Servlet接口

webroot\WEB-INF\web.xmlservlet映射

启动tomcat,将工程发布到tomcat服务器

浏览器访问。

6Servlet细节

Ø  关于URL映射配置

JavaWeb学习笔记(三)之Servlet

Ø  关于Servlet进行URL映射

Servlet规范之所以规定对Servlet进行URL映射,有两点原因?

a.可以为一个Servlet映射多个URL

JavaWeb学习笔记(三)之Servlet

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>元素

JavaWeb学习笔记(三)之Servlet

 

b.简化ServletURL,且可以向客户端隐藏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文件中配置了一个缺省的DefaultServletDefaultServlet帮我们去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访问时,都是执行名称为jspServlet,即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.servletjavax.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中主要的接口与类关系

JavaWeb学习笔记(三)之Servlet

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);

    }

}

 

以上类与接口关系 

JavaWeb学习笔记(三)之Servlet

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方法及doGetdoPost都有一个该类型参数。

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对象,并把它作为参数传给Servletservice方法。

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-提高输出数据效率,ServletOutputStreamPrintWriter先把数据写到缓冲区内。tomcat在调用完Servletservice方法后,会关闭以上两个对象,确保Servlet输出的所有数据被提交给客户。

2-ServletResponse响应正文默认MIME类型为text/plain(纯文本类型)。HttpServletResponse响应正文默认的MIME类型为text/htmlhtml文档类型)。

3-设置响应正文的MIME类型和字符编码时,必须先调用setContentType()setCharacterEncoding方法,然后再调用ServletResponsegetOutputStreamgetWriter方法,或提交缓冲区内的正文数据。满足这样顺序,设置才能生效。

h)HttpServletResponse接口

HttpServletResponse接口是ServletResponse接口的子接口。HttpServlet类重载service方法及doGetdoPost都有一个该类型参数。

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接口,因此在HttpServletGenericServlet类及其子类中可以直接调用ServletConfig方法。

j)ServletContext接口

ServletContextServletServlet容器之间直接通信的接口。

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):根据参数指定的虚拟路径,返回文件系统中一个资源的真实的路径。
webapps下有hello应用,hello应用中有db.conf文件。通过该方法path=/db.conf。可以获得绝对路径…/webapps/hello/db.conf此时/表示当前web应用。

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的日志文件中写错误日志,以及异常的堆栈信息

 

HttpServletGenericServlet类及其子类中可以直接调用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");

javaWeb (开发中经常遇到,加载classes下的、WebRoot下的以及当前类文件夹下的配置文件,需熟悉)

 
//相对的目录时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属性,如果为trueTomcat在运行时会监视Web应用中WEN-INF/classesWEB-INF/lib目录下类文件的改动以及监视Web应用的WEB-INF/web.xml文件的改动。如果监测到类文件或web.xml文件被更新,tomcat则会重新启动Web应用。该属性默认为false。一般在Web应用的开发和调试阶段,为了方便Web应用的调试,reloadable设置trueWeb应用正式发布阶段,设置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次数。



3ServletContextWeb应用范围共享

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应用时,调用该方法。在调用该方法之前,容器会先销毁所有的ServletFilter

每次,如果重新启动Web应用,计数器都会重新从1开始统计访问次数。实际应用中,往往需要统计自Web应用发布后,网页被客户端访问的次数。这需要Web应用每次被终止时,计数器数值被永久存储在一个文件或数据库中,等到Web重新启动时,先从文件或数据库中读取计数器的值,再继续计数。


            案例演示:


可以看出Web应用启动时,Servlet容器先调用MyServletContextListenercontextInitialized方法,再创建,初始化Servlet对象;Web应用终止时,Servlet容器先调用Servletdestroy方法,再调用MyServletContextListenercontextDestroyed方法。由此可知,Web应用的生命周期中,ServletContext对象最早创建,最晚销毁。


5Servlet服务方法抛出异常

Servlet接口的service方法完整定义如下:

publicvoid service(ServletRequest req, ServletResponse res)

throws ServletException, IOException;

该方法声明抛出两个异常:

Ø  ServletException:表示当Servlet进行常规操作时出现的异常

Ø  IOException:表示当Servlet进行IO操作时出现的异常

Ø  UnavailableExceptionServletException子类,表示无法访问当前Servlet异常。如果Servlet由于一些系统级别原因(内存不足或无法访问第三方服务器(DB服务器))不能响应客户请求,就抛出该异常。

Servletservice()方法抛出的异常由Servlet容器捕获,Servlet容器在捕获到异常后,会向客户端发送相应错误信息。


防止页面被客户端缓存
 (***重要***)

客户端缓存浏览器为了能快速向用户展示请求页面,会将服务器端的网页存放到客户端缓存中。多次请求访问服务器端同一网页,只需从缓存中获取该网页即可。

浏览器缓存技术适用于保存服务器端的静态网页,以及不含敏感数据的网页。下面两种情形,服务器不希望网页被客户端缓存。

Ø 网页包含随时被更新的动态内容。此时如果浏览器读取缓存网页,可能展示的是过期网页。

Ø  网页中含有敏感数据。比如银行账号信息或电子邮件内容,如果浏览器把网页保存在本地缓存中,可能被其他未授权的用户访问。

服务器端禁止浏览器缓存网页,可通过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.0HTTP1.1都支持,因此所有浏览器都识别该选项。Expires用于设置网页过期时间,如果为0,表示立即过期。用户每次重复请求访问该网页,浏览器每次都从服务器端获取最新的网页。