Servlet的开发

一、Servlet简介

Servlet是什么?

Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。

使用 Servlet,您可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。

Servlet的主要任务

  • 读取客户端(浏览器)发送的显式的数据。这包括网页上的 HTML 表单,或者也可以是来自 applet 或自定义的 HTTP 客户端程序的表单。
  • 读取客户端(浏览器)发送的隐式的 HTTP 请求数据。这包括 cookies、媒体类型和浏览器能理解的压缩格式等等。
  • 处理数据并生成结果。这个过程可能需要访问数据库,执行 RMI 或 CORBA 调用,调用 Web 服务,或者直接计算得出对应的响应。
  • 发送显式的数据(即文档)到客户端(浏览器)。该文档的格式可以是多种多样的,包括文本文件(HTML 或 XML)、二进制文件(GIF 图像)、Excel 等。
  • 发送隐式的 HTTP 响应到客户端(浏览器)。这包括告诉浏览器或其他客户端被返回的文档类型(例如 HTML),设置 cookies 和缓存参数,以及其他类似的任务。

Servlet核心类图及接口

Java Servlet 是运行在带有支持 Java Servlet 规范的解释器的 web 服务器上的 Java 类。

Servletè§èçæ ¸å¿ç±»å¾

以TOMCAT为例,<CATALINA_HOME>/lib/servlet-api.jar文件为Servlet API的类库文件。

Servlet API主要由两个Java包组成: javax.servlet和javax.servlet.http

  • 在javax.servlet包中定义了Servlet接口及相关的通用接口和类;
  • 在javax.servlet.http包中主要定义了与HTTP协议相关的HttpServlet类,HttpServletRequest接口和HttpServletResponse接口;

Servlet接口

在Servlet接口中定义了5个方法,其中3个方法都是由Servlet容器来调用的,容器会在Servlet的生命周期的不同阶段调用特定的方法:

  • init(ServletConfig): 负责初始化Servlet对象,容器在创建好Servlet对象后,就会调用该方法;
  • service(ServletRquest req, ServletResponse res) :负责相应客户的请求,为客户提供相应服务。当容器接受到客户端要求访问特定Servlet对象的请求时,就会调用该Servlet对象的service()方法;
  • destroy():负责释放Servlet对象占用的资源。当Servlet对象结束声明周期时,容器会调用此方法;

GenericServlet抽象类

GenericServlet抽象类为Servlet接口提供了通用实现,它与任何网络应用层协议无关。

GenericServlet除了实现了Servlet接口,还实现了ServletConfig接口和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类的具体子类必须实现该方法。

GenericServlet类实现了Servlet接口的destroy()方法,但实际什么也没做。

GenericServlet类实现了ServletConfig接口的所有方法。

HttpServlet抽象类

HttpServlet类是GenericServlet类的子类。HttpServlet类为Serlvet接口提供了与HTTP协议相关的通用实现,也就是说,HttpServlet对象适合运行在与客户端采用HTTP协议通信的Servlet容器或者Web容器中。

在我们自己开发的Java Web应用中,自定义的Servlet类一般都扩展自HttpServlet类。

HttpServlet类实现了Servlet接口中的service(ServletRequest , ServletResponse)方法,而该方法实际调用的是它的重载方法HttpServlet.service(HttpServletRequest, HttpServletResponse);

在上面的重载service()方法中,首先调用HttpServletRequest类型的参数的getMethod()方法,获得客户端的请求方法,然后根据该请求方式来调用匹配的服务方法;如果为GET方式,则调用doGet()方法,如果为POST方式,则调用doPost()方法。

HttpServlet类为所有的请求方式,提供了默认的实现doGet(),doPost(),doPut(),doDelete()方法;这些方法的默认实现都会向客户端返回一个错误。

对于HttpServlet类的具体子类,一般会针对客户端的特定请求方法,覆盖HttpServlet类中的相应的doXXX方法。如果客户端按照GET或POST方式请求访问HttpsServlet,并且这两种方法下,HttpServlet提供相同的服务,那么可以只实现doGet()方法,并且让doPost()方法调用doGet()方法。

ServletRequest接口

ServletRequest表示来自客户端的请求;当Servlet容器接收到客户端要求访问特定Servlet的请求时,容器先解析客户端的原始请求数据,把它包装成一个ServletRequest对象。

ServletRequest接口提供了一系列用于读取客户端的请求数据的方法,例如:

  • getContentLength():返回请求正文的长度,如果请求正文的长度未知,则返回-1;
  • getContentType():获得请求正文的MIME类型,如果请求正文的类型为止,则返回null;
  • getInputStream():返回用于读取请求正文的输入流;
  • getLocalAddr() :返回服务端的IP地址;
  • getLocalName() :返回服务端的主机名;
  • getLocalPort() : 返回服务端的端口号;
  • getParameters():根据给定的请求参数名,返回来自客户请求中的匹配的请求参数值;
  • getProtocal(): 返回客户端与服务器端通信所用的协议名称及版本号;
  • getReader() :返回用于读取字符串形式的请求正文的BufferReader对象;
  • getRemoteAddr():返回客户端的IP地址
  • getRemoteHost():返回客户端的主机名
  • getRemotePort() :返回客户端的端口号

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中的“?”后面的内容;

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()方法,提交缓冲区内的正文数据;只有满足这样的操作顺序,所做的设置才能生效。

HttpServletResponse接口

HttpServletResponse接口提供了与HTTP协议相关的一些方法,Servlet可通过这些方法来设置HTTP响应头或向客户端写Cookie。

  • addHeader():向HTTP响应头中加入一项内容
  • sendError():向客户端发送一个代表特定错误的HTTP响应状态代码
  • setHeader():设置HTTP响应头中的一项内容,如果在响应头中已经存在这项内容,则原来的设置被覆盖
  • setStatus():设置HTTP响应的状态代码
  • addCookie():向HTTP响应中加入一个Cookie

在HttpServletResponse接口中定义了一些代表HTTP响应状态代码的静态常量。

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接口中的方法。

ServletContext接口

ServletContext是Servlet与Servlet容器之间直接通信的接口。

Servlet容器在启动一个Web应用时,会为它创建一个ServletContext对象。每个Web应用都有唯一的ServletContext对象,可以把ServletContext对象形象地理解为Web应用的总管家,同一个Web应用中的所有Servlet对象都共享一个ServletContext,Servlet对象可以通过其访问容器中的各种资源。

ServletContext接口提供的方法可以分为以下几种类型:

1、用于在web应用范围内存取共享数据的方法:

  • setAttribute(String name, Object object): 把一个Java对象与一个属性名绑定,并存入到ServletContext中;
  • getAttribute(): 返回指定数姓名的属性值
  • getAttributeNames(): 返回一个Enumeration对象,包含所有存放在ServletContext中的属性名
  • removeAttributes():从ServletContext中删除匹配的属性

2、访问当前Web应用的资源:

  • getContextPath():返回当前Web应用的URL入口
  • getInitParameter():返回Web应用范围内的匹配的初始化参数值。在web.xml中,直接在<web-app>根元素下定义的<context-param>元素表示应用范围内的初始化参数
  • getServletContextName():返回Web应用的名字,即web.xml文件中<display-name>元素的值
  • getRequestDispatcher():返回一个用于向其他WEB组件转发请求的RequestDispatcher对象

3、访问服务器端的文件系统资源:

  • getRealPath():根据参数指定的虚拟路径,返回文件系统中的一个真实的路径
  • getResources():返回一个映射到参数指定的路径的URL
  • getResourceAsStream():返回一个用于读取参数指定的文件的输入流
  • getMimeType():返回参数指定的文件MIME类型

Servlet相关类的关系

与Servlet主动关联的是三个类,分别是ServletConfig,ServletRequest和ServletResponse。这三个类都是通过容器传递给Servlet的;其中,ServletConfig是在Servlet初始化时传给Servlet的,后两个是在请求到达时调用Servlet传递过来的。

对于Request和Response,以TOMCAT为例,tomcat接到请求首先将会创建org.apache.coyote.Request和org.apache.coyote.Response,这两个类是Tomcat内部使用的描述一次请求和相应的信息类,它们是一个轻量级的类,作用就是在服务器接收到请求后,经过简单解析将这个请求快速分配给后续线程去处理。接下来当交给一个用户线程去处理这个请求时又创建org.apache.catalina.connector.Request和org.apache.catalina.connector.Response对象。这两个对象一直贯穿整个Servlet容器直到要传给Servlet,传给Servlet的是Request和Response的Facade类。

Servlet的实际使用

我们自己定义的servlet通常去继承HttpServlet或GenericServlet类。
采用MVC框架的实现中,其基本原理是将所有的请求都映射到一个Servlet,然后去实现servie方法,这个方法也就是MVC框架的入口。

二、Servlet的调用过程

Servlet程序是由WEB服务器调用,web服务器收到客户端的Servlet访问请求后:

① Web服务器首先检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第④步,否则执行第②步。

② 装载并创建该Servlet的一个实例对象。

③ 调用Servlet实例对象的init()方法。

④ 创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。

⑤ WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。

三、Servlet的生命周期

Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:

  • Servlet 初始化后调用 init () 方法。
  • Servlet 调用 service() 方法来处理客户端的请求。
  • Servlet 销毁前调用 destroy() 方法。
  • 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。

init() 方法

init 方法被设计成只调用一次。它在第一次创建 Servlet 时被调用,在后续每次用户请求时不再调用。

当用户调用一个 Servlet 时,就会创建一个 Servlet 实例,每一个用户请求都会产生一个新的线程,适当的时候移交给 doGet 或 doPost 方法。init() 方法简单地创建或加载一些数据,这些数据将被用于 Servlet 的整个生命周期。

init()方法定义如下:

public void init() throws ServletException {
  // 初始化代码...
}

service()方法

service() 方法是执行实际任务的主要方法。Servlet 容器(即 Web 服务器)调用 service() 方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。

每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete 等方法。

service()定义如下:

public void service(ServletRequest request, ServletResponse response) 
      throws ServletException, IOException{
}

service() 方法由容器调用,service 方法在适当的时候调用 doGet、doPost、doPut、doDelete 等方法。所以,您不用对 service() 方法做任何动作,您只需要根据来自客户端的请求类型来重写 doGet() 或 doPost() 即可。

doGet() 和 doPost() 方法是每次服务请求中最常用的方法。

destroy() 方法

destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。

在调用 destroy() 方法之后,servlet 对象被标记为垃圾回收。destroy 方法定义如下所示:

public void destroy() {
    // 终止化代码...
}

下图显示了一个典型的 Servlet 生命周期方案:

  • 第一个到达服务器的 HTTP 请求被委派到 Servlet 容器。
  • Servlet 容器在调用 service() 方法之前加载 Servlet。
  • 然后 Servlet 容器处理由多个线程产生的多个请求,每个线程执行一个单一的 Servlet 实例的 service() 方法。

Servlet çå½å¨æ

四、Servlet实例

Servlet 是服务 HTTP 请求并实现 javax.servlet.Servlet 接口的 Java 类。Web 应用程序开发人员通常编写 Servlet 来扩展 javax.servlet.http.HttpServlet,并实现 Servlet 接口的抽象类专门用来处理 HTTP 请求。

实例代码如下:

// 导入必需的 java 库
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// 扩展 HttpServlet 类
public class HelloWorld extends HttpServlet {
 
  private String message;

  public void init() throws ServletException
  {
      // 执行必需的初始化
      message = "Hello World";
  }

  public void doGet(HttpServletRequest request,
                    HttpServletResponse response)
            throws ServletException, IOException
  {
      // 设置响应内容类型
      response.setContentType("text/html");

      // 实际的逻辑是在这里
      PrintWriter out = response.getWriter();
      out.println("<h1>" + message + "</h1>");
  }
  
  public void destroy()
  {
      // 什么也不做
  }
}

在 web.xml 文件中的 <web-app>...</web-app> 标签内配置Servlet:

<servlet>
	<!-- Servlet的注册名称 -->
	<servlet-name>HelloWorld</servlet-name>
	<!-- Servlet的完整类名 (包名+类名)-->
	<servlet-class>HelloWorld</servlet-class>
</servlet>

<servlet-mapping>
	<!-- Servlet的注册名称 -->
	<servlet-name>HelloWorld</servlet-name>
	<!-- Servlet的对外访问路径 -->
	<url-pattern>/HelloWorld</url-pattern>
</servlet-mapping>

五、Servlet的注意事项

Servlet注册

由于客户端是通过URL地址访问web服务器中的资源,所以Servlet程序若想被外界访问,必须把servlet程序映射到一个URL地址上,这个工作在web.xml文件中使用<servlet>元素和<servlet-mapping>元素完成。

<servlet>元素用于注册Servlet,它包含有两个主要的子元素:<servlet-name>和<servlet-class>,分别用于设置Servlet的注册名称和Servlet的完整类名。

一个<servlet-mapping>元素用于映射一个已注册的Servlet的一个对外访问路径,它包含有两个子元素:<servlet-name>和<url-pattern>,分别用于指定Servlet的注册名称和Servlet的对外访问路径。如下:

<servlet>
	<!-- Servlet的注册名称 -->
	<servlet-name>HelloWorld</servlet-name>
	<!-- Servlet的完整类名 (包名+类名)-->
	<servlet-class>HelloWorld</servlet-class>
</servlet>

<servlet-mapping>
	<!-- Servlet的注册名称 -->
	<servlet-name>HelloWorld</servlet-name>
	<!-- Servlet的对外访问路径 -->
	<url-pattern>/HelloWorld</url-pattern>
</servlet-mapping>

同一个Servlet可以被映射到多个URL上,即多个<servlet-mapping>元素的<servlet-name>子元素的设置值可以是同一个Servlet的注册名。

在Servlet映射到的URL中也可以使用*通配符,但是只能有两种固定的格式:一种格式是“*.扩展名”,另一种格式是以正斜杠(/)开头并以“/*”结尾。

由于匹配符的引入有可能一个虚拟路径会对应多个servlet-mapping,此时哪个最像找哪个servlet,并且*.do级别最低。

load-on-startup

如果在<servlet>元素中配置了一个<load-on-startup>元素,那么WEB应用程序在启动时,就会装载并创建Servlet的实例对象、以及调用Servlet实例对象的init()方法。

<servlet>
	<servlet-name>invoker</servlet-name>
	<servlet-class>xxxxxx.xxx</servlet-class>
	<load-on-startup>2</load-on-startup>
</servlet>

缺省servlet

如果一个servlet的对外访问路径被设置为/,则该servlet就是一个缺省servlet,其他servlet不处理的请求都由它来处理。在conf/web.xml中配置了缺省servlet,对静态资源的访问和错误页面的输出就是由这个缺省servlet来处理的。如果我们自己写一个缺省servlet把web.xml中的缺省servlet覆盖的话,会导致静态web资源无法访问。所以不推荐配置。

在<tomcat的安装目录>\conf\web.xml文件中,注册了一个名称为org.apache.catalina.servlets.DefaultServlet的Servlet,并将这个Servlet设置为了缺省Servlet。当访问Tomcat服务器中的某个静态HTML文件和图片时,实际上是在访问这个缺省Servlet。 设置404页面500页面等提示页面也是由缺省Servlet来执行。

servlet线程安全

产生原因

通常情况下,一个servlet在内存只有一个实例处理请求,当多个请求发送过来的时候就会有多个线程操作该servlet对象,此时可能导致线程安全问题。

① serlvet的成员变量可能存在线程安全问题。如:定义一个成员变量 int i = 0;在doXXX()方法中进行i++操作并输出i值到客户端,此时由于延迟可能导致线程安全问题。

② serlvet操作资源文件时,多个线程操作同一文件引发线程安全问题。如:请求带着一个参数过来,servlet将请求参数写入到一个文件,再读取该文件,将读取到的值打印到客户端上,有可能有线程安全问题。

解决方法

① 利用同步代码块解决问题。缺陷是,同一时间同步代码块只能处理一个请求,效率很低下,所以同步代码块中尽量只包含核心的导致线程安全问题的代码。

② 该servlet实现SingleThreadModel接口,此为一个标记接口,被标记的servlet将会在内存中保存一个servlet池,如果一个线程来了而池中没有servlet对象处理,则创建一个新的。如果池中有空闲的servlet则直接使用。这并不能真的解决线程安全问题。此接口已经被废弃。

两种解决方案都不够完美,所以尽量不要在servlet中出现成员变量。

六、ServletConfig和初始化参数

代表当前Servlet在web.xml中的配置信息。代表servlet配置的对象,可以在web.xml中<servlet>中配置。例如:

<servlet>
  <servlet-name>Demo5Servlet</servlet-name>
  <servlet-class>cn.itheima.Demo5Servlet</servlet-class>
  <init-param>
	<param-name>data1</param-name>
	<param-value>value1</param-value>
  </init-param>
</servlet>

当servlet配置了初始化参数后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用servlet的init方法时,将ServletConfig对象传递给servlet。程序员通过ServletConfig对象就可以得到当前servlet的初始化参数信息

  • String getServletName()  -- 获取当前Servlet在web.xml中配置的名字
  • String getInitParameter(String name) -- 获取当前Servlet指定名称的初始化参数的值
  • Enumeration getInitParameterNames()  -- 获取当前Servlet所有初始化参数的名字组成的枚举
  • ServletContext getServletContext()  -- 获取代表当前web应用的ServletContext对象

七、ServletContext

1、代表当前web应用的对象

WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。

ServletConfig对象中维护了ServletContext对象的引用,开发人员在编写servlet时,可以通过ServletConfig.getServletContext方法获得ServletContext对象。

由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象。

2、作为域对象使用

在不同servlet之间传递数据,作用范围是整个web应用。

生命周期:当web应用被加载进容器时创建代表整个web应用的ServletContext对象。当服务器关闭或web应用被移除出容器时,ServletContext对象跟着销毁。

常用方法:

  • void setAttribute(String,Object);
  • Object getAttribute(String);
  • void removeAttribute(String);

3、初始化参数

在web.xml可以配置整个web应用的初始化参数,利用ServletContext去获得:

<context-param>
	<param-name>param1</param-name>
	<param-value>pvalue1</param-value>
</context-param>
this.getServletContext().getInitParameter("param1")
this.getServletContext().getInitParameterNames()

4、在不同servlet之间进行转发

this.getServletContext().getRequestDispatcher("/servlet/Demo10Servlet").forward(request, response);

方法执行结束,service就会返回到服务器,再到服务器去调用目标servlet,其中request会重新创建,并将之前的request的数据拷贝进去。

5、读取资源文件

由于相对路径默认相对的是java虚拟机启动的目录,所以我们直接写相对路径将会是相对于tomcat/bin目录,所以是拿不到资源的。如果写成绝对路径,当项目发布到其他环境时,绝对路径就错了。

为了解决这个问题ServletContext提供了this.getServletContext().getRealPath("/1.properties"),给进一个资源的虚拟路径,将会返回该资源在当前环境下的真实路径。this.getServletContext().getResourceAsStream("/1.properties"),给一个资源的虚拟路径返回到该资源真实路径的流。

当在非servlet下获取资源文件时,就没有ServletContext对象用了,此时只能用类加载器classLoader.getResourceAsStream("../../1.properties"),此方法利用类加载器直接将资源加载到内存中,有更新延迟的问题,以及如果文件太大,占用内存过大。classLoader.getResource("../1.properties").getPath(),直接返回资源的真实路径,没有更新延迟的问题。

八、参考

https://blog.csdn.net/robinjwong/article/details/17700011

https://www.runoob.com/servlet/servlet-life-cycle.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

codedot

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值