9 servlet

  1. Servlet概述
    1. Servlet概述
      1. Servlet是什么

Servlet是sun公司提供的一门用于开发动态web资源的技术。

按照这套规范写出来的Servlet可以放置到web应用中在Servlet容器中运行。

      1. 开发Servlet步骤

想要开发一个Servlet只需要两个步骤:

(1)写一个类实现javax.servlet接口。

(2)在web.xml中为servlet配置对外访问路径。

  1. 开发第一个Servlet
    1. 写一个类实现Servlet接口
      1. Servlet接口api

接下来我们就手动编写一个Servlet感受一下Servlet开发的过程。

我们用记事本,写一个类实现Servlet接口,我们打开api发现如果直接实现Servlet接口需要实现如下方法,如图-1所示:

图-1

简单介绍下其中重要方法:

init(ServletConfig config)

初始化方法,会在Servlet被创建出来后立即执行,做一些初始化的工作

destroy()

销毁方法,会在Servlet被销毁之前执行,做一些善后工作

service(ServletRequest req, ServletResponse res)

服务方法,每当有请求访问Servlet时,此方法执行,处理请求的代码要写到这个方法里。

      1. GenericServlet抽象类

我们发现这个接口中方法太多了,其实我们可以直接继承Servlet接口的一个默认实现了GenericServlet类,如图-2所示:

图-2

通过观察api,我们发现GenericServlet是个抽象类,实现了Servlet接口中的大部分方法,唯独service方法没有做实现,我们继承GenericServlet需要实现这个Service方法在其中写处理请求的代码。如图-3所示:

图-3

在记事本中编写如下代码,注意写的过程中需要导入包。如图-4所示:

图-4

我们输出当前时间到客户端,service方法有两个参数,ServletRequest代表HTTP请求,ServletResponse代表HTTP响应,我们想要获取客户端发送过来的信息时可以找ServletRequest,现在需要向客户端发送数据就可以使用ServletResponse对象。

通过查询ServletResponse对象的api,发现其中有获取写出数据的流的方法,通过这个方法获取流就可以将数据发送给浏览器。代码如图-5所示:

 

图-5

编写好java文件后,需要进行编译,如图-6所示:

图-6

在编译的过程中发现少了开发包,这是因为我们现在开发的是javaee项目,需要将javaee相关的开发包加入classpath环境变量,这个包在tomcat的支持包中存有,将其加入classpath环境变量即可。如图-7所示:

图-7

再次编译。

报出了警告,是因为Date的toLocaleString方法已经过时,但是我们不关心,到此编译已经完成。编译成功后将包拷入web应用的WEB-INF/classes目录下,如图-8所示:

图-8

 

    1. 配置Servlet的对外访问路径
      1. 在web.xml配置servlet

我们还需要在web.xml中为这个Servlet配置一个对外访问路径。

打开web.xml文件,在根标签下进行如下配置,如图-9所示:

图-9

其中,servlet-class中为配置的Servlet类的全路径名。

servlet-name是为该servlet配置的名称,此名称没有特殊要求,为了便于识别此处取名和类名相同。

url-pattern是为该名称的servlet配置对外访问路径,浏览器可以通过该路径访问此servlet。

启动服务器,通过浏览器访问,如图-10所示:

图-10

发现成功输出了当前时间,多次刷新页面发现每次显示的都是最新的时间,不同的人在不同的时间看到的结果不同,说明这确实是一个动态web资源。

  1. Servlet的调用过程和生命周期
    1. servlet的调用过程
      1. Servlet调用过程图

当我们在访问这个Servlet时,是如何看到时间输出的呢?整个过程是如何工作的呢?我们画图解释,如图-11所示:

图-11

(1)在浏览器输入地址,浏览器先去查找hosts文件,将主机名翻译为ip地址,如果找不到就再去查询dns服务器将主机名翻译成ip地址。

(2)浏览器根据ip地址和端口号访问服务器,组织http请求信息发送给服务器。

(3)服务器收到请求后首先根据Host请求头判断当前访问的是哪台虚拟主机。

(4)服务器根据http请求头中的请求URI判断当前访问的是哪个web应用。

(5)服务器根据http请求头中的请求URI判断当前访问的是web应用中的哪个web资源。

(6)检查web应用的web.xml文件,如果根据路径找到具体的servlet处理类的全路径名交给该servlet处理,如果找不到就交给缺省servlet处理。

(7)这个过程中浏览器只知道自己发出来http请求,不久就收到了http响应,浏览器不知道也不关心服务器内部是如何处理的。浏览器和服务器之间的关系是非常单纯的,只有HTTP协议。

(8)解析请求、封装RequestResponse对象、创建Servlet、调用Service方法都是服务器自动进行的,开发人员只需要写好Servlet配置进容器中即可,无需操心具体的底层实现。---这就是容器啊!多重要!多形象!

    1. servlet的生命周期
      1. servlet生命周期详解

(1)Servlet第一次被访问到时创建对象,创建出来后立即执行init方法执行初始化的操作。

(2)从此以后该对象一直驻留在内存中为后续的对这个Servlet的请求进行服务。

(3)直到服务器关闭或web应用移除出容器时,随着web应用的销毁Servlet对象销毁掉,在销毁之前调用destory方法执行善后工作。

(4)在存活期间,每次对Servlet 的调用都会导致Service方法的执行。

  1. 在myeclipse中开发Servlet
    1. 为什么需要myeclipse
      1. 为什么需要myeclipse

上面的例子中我们用记事本实现了一个Servlet,这样做的目的是为了让大家更好的理解Servlet的本质,但是如果在真实开发中也用记事本开发,可以想见效率一定是非常低的。接下来我们来了解一下如何在Myeclipse环境中开发Servlet

    1. 在Myeclipse中开发Servlet
      1. 第一步:创建servlet

在工程src目录上右键弹出菜单,选择new->Servlet,如图-12所示:

图-12

      1. 第二步:配置servlet类信息

在弹出的对话框中输入Servlet的包名、类名,默认继承HttpServlet,覆盖其中doGet和doPost方法。如图-13所示:

图-13

      1. 第三步:配置serlvet虚拟路径

进入下一界面,选择是否自动配置servlet到web.xml中,一旦勾选,则自动会用输入的信息在web.xml中为该Servlet配置对外访问路径,如图-14所示:

图-14

 

      1. 第四步:编写servlet处理逻辑

点击确定,创建出Servlet,发现该类继承了HttpServlet(此类是Servlet接口的实现类,我们的类继承他,自然也是个Servlet),并且覆写了其中的doGet和doPost方法。

当客户端用get方式访问该Servlet时会导致doGet方法执行

当客户端用post方式访问该Servlet时会导致doPost方法执行

我们只需要写代码处理对应的处理逻辑即可。

很多时候我们的处理代码对于get方式的请求和post方式的请求的处理是相同的,此时可以在doPost中调用doGet();然后将处理代码写在doGet中。这样无论是get还是post请求都可以进行处理了。

编写代码,如图-15所示:

图-15

      1. 第五步:将web应用发布到tomcat中

如图-16所示:

图-16

启动tomcat,如图-17所示:

图-17

      1. 第六步:通过浏览器访问

由于web应用是发布到了webapps中即localhost虚拟主机中,所以按照如下方式访问,注意此处的/Demox不是工程名,而是发布时的指定的web应用名,如图-18所示:

图-18

通过浏览器访问,如图-19所示:

图-19

  1. Servlet的继承结构
    1. Serlvet继承结构
      1. 概述

我们在手写Servlet时继承的是GenericServlet,而用Myeclipse生成的Servlet是继承了HttpServlet,那么他们之间的关系到底是什么样的呢?下面我们讨论下Servlet的继承结构:

      1. Servlet接口

定义了一个servlet应该具有的方法,所有的Servlet都应该直接或间接实现此接口

      1. GenericServlet抽象类

GenericServlet抽象类是对Servlet接口的默认实现,对Serlvet接口中的大部分方法都做了默认实现,只有service方法是一个抽象方法需要继承者自己实现。实现者只需要实现Service方法在其中写处理请求的代码即可。

      1. HttpServlet类

继承自GenericServlet类,在GenericServlet类的基础上对HTTP协议进行了优化,并且实现了其中的service抽象方法,在其中判断了请求的请求方式,并根据请求方式的不同分别调用不同的doXXX()方法。

通常我们在开发Servlet时,直接继承HttpServlet覆盖对应的doGet()doPost()方法即可,一般不推荐直接覆盖service()方法。

 

  1. Servlet对外访问路径配置细节
    1. Servlet配置细节
      1. 基本配置

Servlet需要在web.xml中配置对外访问的路径。如图-20所示:

图-20

其中:

<servlet>标签配置Servlet。

<servlet-mapping>标签配置该Servlet的对外访问路径。

一个<servlet>可以对应多个<servlet-mapping>。

      1. 星号匹配符的使用

可以用*通配符配置<serlvet-mapping>,但是要注意,必须是 *.后缀 或者 /开头的以/*结尾的路径。

由于匹配符的引入有可能一个虚拟路径会对应多个<servlet-mapping>,此时的匹配优先原则为:哪个最像找哪个,*.后缀 优先级最低。

思考:

对于如下的一些映射关系:Servlet1 映射到 /abc/* Servlet2 映射到 /* Servlet3 映射到 /abc Servlet4 映射到 *.do 问题:当请求URL为“/abc/a.html”,“/abc/*”和“/*”都匹配,哪个servlet响应 Servlet引擎将调用Servlet1。当请求URL为“/abc”时,“/abc/*”和“/abc”都匹配,哪个servlet响应 Servlet引擎将调用Servlet3。当请求URL为“/abc/a.do”时,“/abc/*”和“*.do”都匹配,哪个servlet响应 Servlet引擎将调用Servlet1。当请求URL为“/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应 Servlet引擎将调用Servlet2。当请求URL为“/xxx/yyy/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应 Servlet引擎将调用Servlet2。

 

      1. 缺省Servlet

路径中有一个特殊的配置“/”,如果一个servlet的对外访问路径被设置为/,则该servlet就是一个缺省servlet,其他servlet不处理的请求都由它来处理。

在conf/web.xml(通用web.xml,参考tomcat章节)中配置了缺省servlet,对静态资源的访问和错误页面的输出就是由这个缺省servlet来处理的。

如果我们自己写一个缺省servlet把爸爸web.xml中的缺省servlet覆盖的话,会导致静态web资源无法访问。所以不推荐自己配置缺省Servlet。

  1. 创建EasyMall注册Servlet
    1. 注册Servlet实现
      1. 开发注册Servlet

在前面的学习过程中我们已近开发好了EasyMall的注册页,现在我们学完了Servlet,可以试着开发后台代码了。

首先我们将之前开发好的注册页面导入工程中,放置在web应用根目录下。

创建注册用的RegistServlet,并配置对外访问路径。如图-21所示:

图-21

修改注册页面中注册表单的提交地址指向RegistServlet。如图-22所示:

图-22

通过测试发现表单可以正确提交到Servlet中。如图-23所示:

图-23

      1. 引申出的问题

所谓的注册其实就是获取提交过来的请求参数中的注册信息,进行处理后保存在服务器数据库中。

遇到的第一个问题就是,如何获取客户端提交的请求参数。

我们注意看doGet和doPost方法,他们有两个参数,其中HttpServletRequest代表请求,HttpServletResponse代表Http响应。

既然我们需要的是请求参数,根据面向对象的思想,我们可以想见HttpServletRequest必然提供了对应的方法。

  1. Request对象
    1. Request的继承结构
      1. Request的继承结构

我们查看api,如图-24所示:

图-24

虽然我们一直简称为Request,但实际上代表请求的接口为ServletRequest,其中定义了http请求相关的方法。

ServletRequest有一个子类HttpServletRequest,在ServletRequest的基础上增加了很多和http协议相关的方法。

既然Request代表HTTP,那么Http请求相关的请求行请求头实体内容等信息都可以通过这个对象获得。

    1. Request获取客户机信息
      1. 通过request对象获取客户机相关的信息

getRequestURL方法 -- 返回客户端发出请求完整URL

getRequestURI方法 -- 返回请求行中的资源名部分

getQueryString方法 -- 返回请求行中的参数部分

getRemoteAddr方法 -- 返回发出请求的客户机的IP地址

getMethod方法 -- 返回客户机的请求方式

getContextPath方法 -- 获得当前web应用的虚拟目录名称

    1. Request获取请求头信息
      1. 通过request对象获取请求头相关的信息

getHeader(name)方法 --- String

getHeaders(String name)方法 --- Enumeration<String>

getHeaderNames方法 --- Enumeration<String>

getIntHeader(name)方法  --- int

getDateHeader(name)方法 --- long(日期对应毫秒)

    1. Request获取请求参数和乱码解决
      1. 获取请求参数。

getParameter(String name) -- String 通过name获得值

getParameterValues(String name) -- String[] 通过name获得多值 如: 爱好

getParameterNames() -- Enumeration<String> 获得所有请求参数的name

getParameterMap() -- Map<String,String[ ]> key :name value: 多值

我们试着通过这些方法去获取请求参数。如图-25所示:

图-25

经过测试,发现如果请求参数中是英文字符,是可以正常获取的。

但如果请求参数是中文,获取到的却是乱码。,入图-26所示:

图-26

      1. 请求参数乱码的原因和解决方法

这些乱码是如何产生的呢?又该如何解决呢?

我们来画图分析一下乱码产生的原理。

图-27

我们知道计算机中并不能真的存储字符,计算机的底层所有的数据都是由01这样的二进制组成的。

将字符映射成对应二进制的表叫做码表。

而大部分情况下乱码都是由于编码-解码过程中码表不一致产生的。

我们来分析一下请求乱码产生的原因。

首先浏览器是用什么码表来将字符转编码成二进制进行发送的呢?浏览器用什么码表来打开表单页面就用什么编码来发送数据。当前我们的注册页面指定了用utf-8来打开。

如图-28所示:

图-28

这就决定了浏览器是用utf-8打开的页面,浏览器在提交表单时是用utf-8编码的。

而tomcat默认情况下会使用iso8859-1来进行解码。

我们知道全世界的码表都兼容iso8859-1,所以英文处理是没有问题的。

但是iso8859-1中并没有中文,iso8859-1对于无法处理的字节都使用?替代,所以我们看到打印的是很多的“?”。

那么该如何解决这类乱码呢?

既然这个问题是服务器处理的过程中产生的,那么只要通知服务器不要使用iso8859-1而是使用正确的utf-8解析数据就可以了。

ServletRequest中提供了setCharacterEncoding方法,可以通知服务器在处理请求时使用哪个指定编码。如图-29所示:

图-29

但是要注意这行代码必须在获取任何请求参数之前执行,如果之前获取过任何请求参数,则此方法失效。

我们设置这行代码,再进行测试,发现乱码已经解决。如图-30所示:

图-30

之前我们的表单是POST提交,我们再将请求方式改为GET,再次测试,发现乱码又出现了。如图-31所示:

图-31

很奇怪,明明已经设置过编码,为什么对POST可以,但GET不行呢?

原来setCharacterEncoding是通知服务器以什么编码处理请求实体内容中的数据,在POST提交时,数据在请求的实体内容中,这行方法可以起作用,而GET提交时,由于请求参数是赋在地址栏后的,这行代码管不到,所以仍然有乱码。

那么应该如何来处理这种乱码呢?回到问题的本质,由于客户端发送时使用的是utf-8编码而服务器用iso8859-1解码造成了乱码,虽然字符已经乱掉了,但底层的字节仍然是正确的,我们只要将乱码字符getBytes(“iso8859-1”)转换为字节,就是正确的字节,再将这些字节new String(bytes,“utf-8”)按照正确的码表编码,就可以转换回正确的字符了。从而解决了乱码。如图-32所示:

图-32

这种方式乱码的解决是从原理上手动编解码解决的乱码,对GET和POST方式的提交都有效。

  1. EasyMall获取用户请求参数处理
    1. Easymall注册功能请求参数处理
      1. 代码实现

学会了如何处理请求参数,我们现在可以获取用户提交的注册相关信息了,如图-33所示:

图-33

      1. 引申出的问题

在如上处理中们将处理用的编码写死在了程序中,这是很不好的编程习惯,一旦未来需要修改工程的编码集还需要来修改源代码。

对于这种可能修改的程序相关的信息,最好不要写死在程序中,而应该采取可配置的方式配置到配置文件中。

我们当前可以自己写配置文件来读取,但其实我们也可以使用Servlet本身的机制将信息配置到web.xml中。

  1. Response
    1. Response概述
      1. Response概述

Servlet中应该如何向用户输出数据呢?在doGet和doPost方法的参数中,HttpServletRequest代表的是http请求,而HttServletResponse代表的是http响应。想要获取请求中的信息时使用HttpServletRequest对象,而有数据需要发送给客户端时,就要用到HttpServletResponse对象了。

    1. Response继承结构
      1. Response继承结构

虽然我们经常简称为response,实际上是ServletResponse接口,其中定义了很多和响应对象相关的方法,HttpServletResponse是ServletResponse接口的子接口,在ServletResponse的基础上增加了很多和http协议相关的方法。如图-40所示:

图-40

    1. Response常用方法
      1. 设置状态码

setStatus(int sc)

setStatus(int sc, String sm)

      1. 设置响应头

setIntHeader(String name, int value)

setHeader(String name, String value)

setDateHeader(String name, long date)

      1. 获取输出流

PrintWriter getWriter()

ServletOutputStream getOutputStream();

    1. Response输出信息到客户端
      1. 输出信息到客户端api

查询api,在Response向外输出数据的方法有如下两个:

PrintWriter getWriter()

ServletOutputStream getOutputStream();

其中getWriter获取的是字符流,可以输出字符数据到客户端。

getOutputStream获取的是字节流,可以输出字节数据到客户端。

我们现在要将字符数据发送给客户端,可以调用getWriter方法向其中输出数据

经测试可以正确的输出。如图-41所示:

图-41

接着我们测试中文。发现输出时产生了乱码。如图-42所示:

图-42

      1. 响应乱码处理

这个乱码是如何产生的呢?乱码的产生大多是由于编码和解码时的码表不同产生的。

那么服务器是以什么码表来发送数据呢?我们发现乱码是以“?”的形式出现的。根据我们的经验,这种问题多半是由ISO8859-1编码导致的。

确实是的,如果不指定,服务器默认将用iso8859-1进行编码发送数据。浏览器用什么码表打开呢?一般来说如果不指定,浏览器默认会用所在的操作系统的平台码,我们当前的中文系统中,默认就是使用GB2312作为解码码表的。

首先iso8859-1中没有中文,对于无法表示的字符,iso8859-1会用“?”来替代,所以真正发送给浏览器的数据其实是“?”,世界上所有的码表都默认兼容iso8859-1,所以gb2312认识,显示为了“?”。如图-43所示:

图-43

在解决这个问题时,可以通过设置response.setCharacterEncoding(“gbk”)来指定服务器发送数据时使用的码表。同时要注意,此行代码必须出现在任何输出数据的代码之前,如果在这行代码之前已经有任何数据写入给了response,则此行代码无效。

设置过后再重新测试。发现仍然是乱码,但不再是“??”而是变成了“涓浗”。如图-44所示:

图-44

这种类型的乱码是怎么发生的呢?我们接着分析。服务器用utf-8发送数据给浏览器,而浏览器用平台码(当前为gbk)gbk打开自然产生了乱码。如图-45所示:

 

图-45

这种乱码的产生是由于浏览器没有使用正确的编码打开造成的,那么我们该如何控制浏览器用指定码表打开数据呢?

在http协议中有一个响应头叫做Content-Type可以用来通知浏览器当前服务器发送的数据的格式,如果是字符格式的数据还可以指定解析时使用的码表。所以我们可以通过如下方法通知浏览器用指定码表打开发送的数据,代码如下,经测试没有乱码。

我们通过response.setHeader("Content-Type", "text/html;charset=utf-8");通知服务器发送数据时的码表。

通过response.setCharacterEncoding("utf-8");通知浏览器解析时使用的码表。

两码相同就不会有乱码了。

如图-46所示:

图-46

另外response提供了setContentType()快捷方法,在它的底层,会同时做上面两件事,所以可以一行代码解决response产生的乱码问题。如图-47所示:

图-47

      1. Response输出数据时的细节

(1)getOutputStream和getWriter这两个方法互相排斥,调用了其中的任何一个方法后,就不能再调用另一方法。      (2)Servlet程序向ServletOutputStream或PrintWriter对象中写入的数据将被Servlet引擎从response里面获取,Servlet引擎将这些数据当作响应消息的正文,然后再与响应状态行和各响应头组合后输出到客户端。     (3)Serlvet的service方法结束后,Servlet引擎将检查getWriter或getOutputStream方法返回的输出流对象是否已经调用过close方法,如果没有,Servlet引擎tomcat将调用close方法关闭该输出流对象。

    1. EasyMall提示信息实现
      1. 代码实现

根据上面所学关于Resonse的知识,我们现在可以修改程序在校验数据出错时,向外输出提示信息了。如图-48所示:

图-48

      1. 引申出的问题

对于成功通过了数据校验的请求,我们应该将数据存储到数据库中,我们目前还没有学习数据库,所以可以用xml文件模拟数据库实现功能。

我们在工程中创建users.xml文件,放置在src目录下。如图-49所示:

图-49

当用户注册时将用户信息通过dom4j写入xml中。

首先将dom4j包引入工程。

写代码更新users.xml

package com.easymall;

 

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.Writer;

 

import javax.servlet.ServletContext;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

 

import org.dom4j.Document;

import org.dom4j.DocumentHelper;

import org.dom4j.Element;

import org.dom4j.io.OutputFormat;

import org.dom4j.io.SAXReader;

import org.dom4j.io.XMLWriter;

 

public class RegistServlet extends HttpServlet {

 

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//读取web.xml中的编码配置

ServletContext context = this.getServletContext();

String encode = context.getInitParameter("encode");

//请求参数编码设置

request.setCharacterEncoding(encode);

//响应输出编码配置

response.setContentType("text/html;charset=utf-8");

String username = request.getParameter("username");

String password = request.getParameter("password");

String password2 = request.getParameter("password2");

String nickname = request.getParameter("nickname");

String email = request.getParameter("email");

String valistr = request.getParameter("valistr");

 

//验证验证码

//TODO 验证验证码是否正确

//验证字段非空

if(username == null || "".equals(username)){

response.getWriter().write("用户名不能为空!");

return;

}

if(password == null || "".equals(password)){

response.getWriter().write("密码不能为空!");

return;

}

if(password2 == null || "".equals(password2)){

response.getWriter().write("确认密码不能为空!");

return;

}

if(nickname == null || "".equals(nickname)){

response.getWriter().write("昵称不能为空!");

return;

}

if(email == null || "".equals(email)){

response.getWriter().write("邮箱不能为空!");

return;

}

//验证邮箱格式是否正确

if(!email.matches("^\\w+@\\w+(\\.\\w+)+$")){ response.getWriter().write("邮箱格式不正确!");

return;

}

 

//存入数据库

try {

//解析xml

SAXReader reader = new SAXReader();

Document dom = reader.read("users.xml");

Element root = dom.getRootElement();

//凭空创建userEle保存用户信息

Element userEle = DocumentHelper.createElement("user");

userEle.setAttributeValue("username", username);

userEle.setAttributeValue("password", password);

userEle.setAttributeValue("nickname", nickname);

userEle.setAttributeValue("email", email);

//挂载到根节点

root.add(userEle);

//更新xml

XMLWriter wrtier = new XMLWriter(new FileOutputStream("users.xml"),OutputFormat.createPrettyPrint());

wrtier.write(dom);

wrtier.close();

} catch (Exception e) {

e.printStackTrace();

throw new RuntimeException(e);

}

}

 

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request,response);

}

 

}

在实现的过程中,我们发现无法读取到这个xml文件。如图-50所示:

图-50

这是为什么呢?

我们观察到,如果写一个相对路径程序是到tomcat的bin目录中寻找users.xml文件的,路径错误。

我们修改程序,写一个绝对路径,发现访问的是tomcat所在的磁盘根目录。路径错误。

如图-51所示:

图-51

为什么会这样呢?

原来,当java程序在计算路径的时候,如果写的是相对路径则会基于程序的启动目录进行相对路径计--对于web应用,由于程序是运行在tomcat中,而tomcat是由tomcat/bin中的startup.bat启动的,自然是相对于这里的。

如果写的是一个绝对路径,则访问的是程序启动根目--对于tomcat则是tomcat所在的根目录。

这两个位置当然找不到xml文件。

那么该如何读取这个资源文件呢?其实我们知道,这个xml文件就在E:\resource\tarena\EasyMall\WebRoot\WEB-INF\classes\users.xml,如果我们直接写这个盘符开始的绝对路径可不可以呢?

经测试是可以的。

但是这种写法将路径写死在了程序中的,一旦换了发布环境,这个路径很可能是错的。非常常见的场景是,开发阶段我们在自己的计算机中进行开发,我们把路径写成自己电脑中文件所在的路径,而开发完成后发布到生产环境服务器中,此时路径往往是错误的。所以这种写法虽然可以但是仍然不好。

相对路径、绝对路径、盘符开始的绝对路径都不行,我们发现陷入了一个路径难题,到底该如何读取这个资源文件呢?

这里就需要用到一个特别的对象ServletContext了。

Servlet调用过程

防盗链

请求参数的乱码问题

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

岁月玲珑

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

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

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

打赏作者

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

抵扣说明:

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

余额充值