Servlet的学习(六)

  本篇接上篇《Servlet的学习(五)》,继续从ServletContext对象中的方法进行学习,在这一篇中,我们重点关注的是ServletContext对象中对于在web工程中的资源文件的读取方法。

  ServletContext类中有这么四个方法:getRealPath(String path),getResource(String path),getResourceAsStream(String path),getResourcePaths(String path),这四个方法都使用web工程下某个web资源路径的字符串表现形式作为参数,而每个方法返回不同的类型,我们通过这四个方法之一可以获取某个资源,并对其进行读取和修改操作。

  假设我们的【myservlet】web工程中有一个数据库的配置文件:database.properties,在这个数据库中已经有了一些参数,而我们在web工程中希望读取这个配置文件中的有关信息:

  

  先来看看ServletContext中的getResourceAsStream()方法,这个方法返回InputStream对象。由于我们的配置文件为properties文件,所以可以用Properties对象来装载这个输入流,代码如下:

 1 public void doGet(HttpServletRequest request, HttpServletResponse response)
 2             throws ServletException, IOException {
 3         ServletContext context = this.getServletContext();
 4         InputStream in = context.getResourceAsStream("/database.properties");
 5
 6         Properties prop = new Properties();
 7         prop.load(in);
 8
 9         String url = prop.getProperty("url");
10         String username = prop.getProperty("username");
11         String password = prop.getProperty("password");
12         System.out.println(url);
13         System.out.println(username);
14         System.out.println(password);
15     }

最后在浏览器中访问这个Servlet,那么在MyEclipse的控制台上能看到的数据正好是database.properties中我们配置的信息:

  

  接下来看看ServletContext中的getRealPath()方法,这个方法返回String对象。由于我们的配置文件为properties文件,所以可以用Properties对象来装载这个输入流,代码如下:

 1 ServletContext context = this.getServletContext();
 2         String filePath = context.getRealPath("/database.properties");
 3
 4         FileInputStream fis = new FileInputStream(filePath);
 5         Properties prop = new Properties();
 6         prop.load(fis);
 7
 8         String url = prop.getProperty("url");
 9         String username = prop.getProperty("username");
10         String password = prop.getProperty("password");
11         System.out.println(url);
12         System.out.println(username);
13         System.out.println(password);

最后在浏览器中访问这个Servlet,那么在MyEclipse的控制台上能看到的数据正好是database.properties中我们配置的信息:

  

使用getRealPath()方法的好处在于这个方法还可以获取文件名,而getResourceAsStream()方法就只能获取文件流了。例如获取文件名:

1 ServletContext context = this.getServletContext();
2         String filePath = context.getRealPath("/WEB-INF/web.xml");
3         System.out.println(filePath);
4
5         if(filePath == null) {
6             System.out.println("所找文件不存在!");
7         }
8         String fileName = filePath.substring(filePath.lastIndexOf("\\"));
9         System.out.println("文件为:"+fileName);

接着来看看ServletContext中的getResource()方法,这个方法返回URL对象。而URL对象具有打开到此 URL 的连接并返回一个用于从该连接读入的 InputStream的openStream()方法。由于我们的配置文件为properties文件,所以可以用Properties对象来装载这个输入流,代码如下:

 1 ServletContext context = this.getServletContext();
 2         URL fileUrl = context.getResource("/database.properties");
 3         InputStream in = fileUrl.openStream();
 4
 5         Properties prop = new Properties();
 6         prop.load(in);
 7
 8         String url = prop.getProperty("url");
 9         String username = prop.getProperty("username");
10         String password = prop.getProperty("password");
11         System.out.println(url);
12         System.out.println(username);
13         System.out.println(password);

最后在浏览器中访问这个Servlet,那么在MyEclipse的控制台上能看到的数据正好是database.properties中我们配置的信息:

以上说完了几种通过ServletContext对象来读取web应用下的某个资源文件,只要通过读取的方法,并将资源相对于web工程的路径作为参数传入其中便可。我们上述的例子都是直接在web工程中,或者web工程的某个目录下,而如果我们把某个web资源放置在MyEclipse中的【src】目录中,那么该如何读取呢:

  

  我们说过,这个web应用在发布时,会将【src】目录下的.java文件编译成为.class字节码文件,由服务器自动将这些字节码文件放置在该web应用中的【WEB-INF】下的【classes】目录里,如果没有【classes】目录,服务器会自动帮我们创建,因此,只要是放置在【src】目录中的资源,最后也会被服务器自动放置在【classes】目录中,这样我们可以继续通过ServletContext对象来获取:

 1 ServletContext context = this.getServletContext();
 2         InputStream in = context.getResourceAsStream("/WEB-INF/classes/database.properties");
 3
 4         Properties prop = new Properties();
 5         prop.load(in);
 6
 7         String url = prop.getProperty("url");
 8         String username = prop.getProperty("username");
 9         String password = prop.getProperty("password");
10         System.out.println(url);
11         System.out.println(username);
12         System.out.println(password);

  

  关于web工程下某个web资源在不同位置下的问题:

  问题一:我们为什么不能用传统方式,如FileInputStream或者File对象来直接获取web工程中的资源呢?其实也是可以的,但是有个路径的问题,Servlet中方法所需要的路径都是相对于web应用的路径,而传统的FileInputStream等等中方法所需的路径参数都是相对于虚拟机的路径。而又因为我这个web应用是从MyEclipse中的Tomcat里启动的,所以这时候的虚拟机目录其实是Tomcat中的【bin】目录。所以如果想用传统方式读取文件必须每次都将文件放置在Tomcat的【bin】目录下, 这是多么麻烦的事,因此我们开发web工程就应该使用web工程中的方法来读取文件!但是,这却又引出了问题二。。。

  问题二:当我们web工程中有别的非Servlet的类时,比如JavaBean,当JavaBean需要连接数据库时,这就是非Servlet对象读取web工程中的资源文件了,不能用ServletContext来读取,问题一种也说过不能用传统方式如FileInputStream来读取,那么该如何读取呢?

  答案是:类加载器!关于类加载器的学习请好好查阅相关文章,也是很重要的。由于在【src】目录下的Java程序经过编译成字节码class文件,如果要用到这些类,Java虚拟机需要先将这些字节码文件加载到内存中才可以使用,而这个过程就是由类加载器来完成。因此这就有一个知识点,如果我们将某个web资源放置在【src】目录下,因为这是个web工程,服务器会自动将各个字节码文件重新放置在【classes】目录下, 而这个web资源也会重新被服务器放置在【classes】目录下,那么类加载器能加载【classes】目录下所有的字节码文件,同时,同处在这个目录下的web资源也会被类加载器加载进内存,这时我们就可以使用类加载器读取该web资源了。

  例:在【myservlet】的dao包中创建一个Student的JavaBean对象,并在src【目录下】创建一个student的配置文件student.properties,而这个配置文件内容如下图所示:

  

在Student类中,我们需要通过类加载器来获取输入流来读取这个文件:

 1 public class Student {
 2     public void getStudent() throws IOException {
 3         ClassLoader loader = Student.class.getClassLoader();
 4         InputStream in = loader.getResourceAsStream("/student.properties");
 5
 6         Properties prop = new Properties();
 7         prop.load(in);
 8
 9         String studentName = prop.getProperty("name");
10         String studentAge = prop.getProperty("age");
11         System.out.println(studentName+":"+studentAge);
12     }
13 }

  另外创建一个Servlet作为可以供浏览器访问的对象,在该Servlet中创建Student的示例来获取配置文件中的内容,这样就达到了从非Servlet对象读取web资源内容并向Servlet对象传递数据:

1 public class ServletDemo3 extends HttpServlet {
2     public void doGet(HttpServletRequest request, HttpServletResponse response)
3             throws ServletException, IOException {
4
5         Student student = new Student();
6         student.getStudent();
7     }
8 }

从浏览器中访问该Servlet,可以看到通过类加载器读取的配置文件中的内容:

  

  注意,这种方法只能是web资源放置在【src】目录中才可以使用,如果要读取的web资源是放置在web工程的目录下,使用类加载器也还是无法读取,因为类加载器只能读取类目录下的文件,这时候非Servlet类就无法读取资源文件,只能使用ServletContext来读取了。

  方立勋老师说:“类加载器只能加载【classes】目录下的所有文件一次,这样在服务器运行web工程的过程中,如果我们修改【classes】目录下的student.properties配置文件,则由于类加载器不再加载,因此使用类加载器的方式不能读取修改后的内容”

但是我修改后,还是可以使用类加载器的方式读取classes】目录下修改后的student.properties配置文件,难道是因为JDK7的原因吗?

  不过不管是什么原因,方立勋老师针对他的问题所采取的解决方案还是值得学习的,他采用先用类加载器获取该配置文件的路径,然后再采用传统方式获取这个文件的输入流。所以在Student中的getStudent()方法代码改为:

 1 public class Student {
 2     public void getStudent() throws IOException {
 3         ClassLoader loader = Student.class.getClassLoader();
 4         URL fileUrl = loader.getResource("student.properties");
 5         String filePath = fileUrl.getPath();
 6
 7         FileInputStream fis = new FileInputStream(filePath);
 8         Properties prop = new Properties();
 9         prop.load(fis);
10
11         String studentName = prop.getProperty("name");
12         String studentAge = prop.getProperty("age");
13         System.out.println(studentName+":"+studentAge);
14 }
15 }

这种方式还有一种好处就是,如果要读取的文件过大,而之前通过类加载器将大文件加载进内存就容易导致内存溢出,所以还是采用这种方式比较好。

  最后再说明一点,如果是在非Servlet类中采用类加载器获取【classes】目录中的资源,方法参数的路径只需要是相对于【src】目录即可。

  ServletContext对象中的getServletContextName()方法时返回的是在web.xml文件中使用<display-name>标签所设置的内容。使用这个标签可以为web应用设置一个名称,可以作用于路径的编写上(凡事不要都写死嘛╰( ̄▽ ̄)╭)。

时间: 2024-12-06 22:20:37

Servlet的学习(六)的相关文章

Servlet的学习(四)

在本篇的Servlet的学习中,主要来学习由使用MyEclipse来开发Servlet的一些小细节. 细节一:在web.xml中可以对同一个Servlet配置多个对外访问路径,并如果在web.xml中配置的信息服务器会自动加载部署,而如果是在Servlet中进行程序代码的修改,则每次都要重新部署. 首先,在使用MyEclipse创建Servlet后,会根据所创建的Servlet进行到web.xml文件的映射,如下图所示: 经过这个映射之后,在web.xml文件中就自动生成了这个Servlet的配

springMVC3学习(六)--SimpleFormController

SimpleFormController提交表单流程例如以下: login.jsp <form action="login" method="post"> 用户名:<input type="text" name="username"/></br> 密码:<input type="password" name="password"/><

Servlet的学习(十一)

在上一篇<Servlet的学习(十)>中介绍了HttpServletRequest请求对象的一些常用方法,而从这篇起开始介绍和学习HttpServletRequest的常用功能. 使用HttpServletRequest可以防止盗链行为,什么是盗链行为,比如说在一个别的网站上超链接,指向我们的网页中的某个数据,这样从他的网页上就可以直接进入到我的某个页面,无需从我的指定路口进入: 例如在一个简单的1.html文件中加入了我的[myservlet]web应用下的某个Servlet访问的超链接:

Servlet的学习(二)

本篇接上一篇<Servlet的学习(一)>,讲述如何利用MyEclipse来创建web工程, 同时讲述如何在MyEclipse中配置Tomcat服务器. 在MyEclipse中,新建“Web Project”,会看到: 我们需要注意的有以下几点: [Project Name]:工程名,代表了这个web应用所在目录名,当在服务器中发布这个web应用时,在Tomcat的[webapps]目录下,就会产生这个目录,所以对于截图来说,就会有一个[myservlet]目录. [Source folder

C#多线程学习(六) 互斥对象

C#多线程学习(六) 互斥对象 如何控制好多个线程相互之间的联系,不产生冲突和重复,这需要用到互斥对象,即:System.Threading 命名空间中的 Mutex 类. 我们可以把Mutex看作一个出租车,乘客看作线程.乘客首先等车,然后上车,最后下车.当一个乘客在车上时,其他乘客就只有等他下车以后才可以上车.而线程与Mutex对象的关系也正是如此,线程使用Mutex.WaitOne()方法等待Mutex对象被释放,如果它等待的Mutex对象被释放了,它就自动拥有这个对象,直到它调用Mute

Servlet的学习之Request请求对象(3)

本篇接上一篇,将Servlet中的HttpServletRequest对象获取RequestDispatcher对象后能进行的[转发]forward功能和[包含]include功能介绍完. 首先来看RequestDispatcher对象的“转发”功能: 在<Servlet的学习(五)>中说过,使用ServletContext对象的getRequestDispatcher方法可以获得转发对象RequestDispatcher对象,将请求进行转发给其他的Servlet或者JSP处理,同时在该篇的结

Servlet的学习(九)

本篇来说明响应对象HttpServletResponse对象的最后一点内容. 首先来看响应对象控制浏览器定时刷新,在我的web应用[myservlet]中创建Servlet,在该Servlet中设置响应头,定时刷新的代码很简单: response.setHeader("refresh", "3 "); //3秒刷新一次 就可告知浏览器3秒刷新一次网页.当然“Refresh”响应头还是可以定时跳转到指定页面,如下代码: response.setHeader("

Servlet的学习(八)

本篇接上一篇<Servlet的学习(七)>,继续从HttpServletResponse响应对象来介绍其方法和功能. 使用setHeader方法结合HTTP协议的content-disposition响应头可以将某些web资源以下载方式回传给客户端.但是在下载中文文件的时候会有一些问题,这问题会怎么发生呢? 我们现在来进行从客户端向服务器端下载一个图片文件,先在MyEclipse的自创建[myservlet]web工程下准备一个图片文件,放置在web目录下的[download]文件夹中: 创建

Beaglebone Back学习六(Can总线测试)

Can总线测试 1 Can总线 控制器局域网 (Controller Area Network, 简称 CAN 或 CANbus)是一种通信协议,其特点是允许网络上的设备直接互相通信,网络上不需要主机(Host)控制通信.是由研发和生产汽车电子产品著称的德国BOSCH公司开发了的,并最终成为国际标准(ISO11898).CAN总线原理是通过CAN总线.传感器.控制器和执行器由串行数据线连接起来.它不仅仅是将电缆按树形结构连接起来,其通信协议相当于ISO/OSI参考模型中的数据链路层,网络可根据协