Servlet的学习之ServletContext(2)
本篇接上篇《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对象来装载这个输入流,代码如下:
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletContext context = this.getServletContext();
InputStream in = context.getResourceAsStream("/database.properties"); Properties prop = new Properties();
prop.load(in); String url = prop.getProperty("url");
String username = prop.getProperty("username");
String password = prop.getProperty("password");
System.out.println(url);
System.out.println(username);
System.out.println(password);
}
最后在浏览器中访问这个Servlet,那么在MyEclipse的控制台上能看到的数据正好是database.properties中我们配置的信息:
接下来看看ServletContext中的getRealPath()方法,这个方法返回String对象。由于我们的配置文件为properties文件,所以可以用Properties对象来装载这个输入流,代码如下:
ServletContext context = this.getServletContext();
String filePath = context.getRealPath("/database.properties"); FileInputStream fis = new FileInputStream(filePath);
Properties prop = new Properties();
prop.load(fis); String url = prop.getProperty("url");
String username = prop.getProperty("username");
String password = prop.getProperty("password");
System.out.println(url);
System.out.println(username);
System.out.println(password);
最后在浏览器中访问这个Servlet,那么在MyEclipse的控制台上能看到的数据正好是database.properties中我们配置的信息:
使用getRealPath()方法的好处在于这个方法还可以获取文件名,而getResourceAsStream()方法就只能获取文件流了。例如获取文件名:
ServletContext context = this.getServletContext();
String filePath = context.getRealPath("/WEB-INF/web.xml");
System.out.println(filePath); if(filePath == null) {
System.out.println("所找文件不存在!");
}
String fileName = filePath.substring(filePath.lastIndexOf("\\"));
System.out.println("文件为:"+fileName);
接着来看看ServletContext中的getResource()方法,这个方法返回URL对象。而URL对象具有打开到此 URL
的连接并返回一个用于从该连接读入的 InputStream
的openStream()方法
。由于我们的配置文件为properties文件,所以可以用Properties对象来装载这个输入流,代码如下:
ServletContext context = this.getServletContext();
URL fileUrl = context.getResource("/database.properties");
InputStream in = fileUrl.openStream(); Properties prop = new Properties();
prop.load(in); String url = prop.getProperty("url");
String username = prop.getProperty("username");
String password = prop.getProperty("password");
System.out.println(url);
System.out.println(username);
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();
InputStream in = context.getResourceAsStream("/WEB-INF/classes/database.properties"); Properties prop = new Properties();
prop.load(in); String url = prop.getProperty("url");
String username = prop.getProperty("username");
String password = prop.getProperty("password");
System.out.println(url);
System.out.println(username);
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类中,我们需要通过类加载器来获取输入流来读取这个文件:
public class Student {
public void getStudent() throws IOException {
ClassLoader loader = Student.class.getClassLoader();
InputStream in = loader.getResourceAsStream("student.properties"); Properties prop = new Properties();
prop.load(in); String studentName = prop.getProperty("name");
String studentAge = prop.getProperty("age");
System.out.println(studentName+":"+studentAge);
}
}
另外创建一个Servlet作为可以供浏览器访问的对象,在该Servlet中创建Student的示例来获取配置文件中的内容,这样就达到了从非Servlet对象读取web资源内容并向Servlet对象传递数据:
public class ServletDemo3 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { Student student = new Student();
student.getStudent();
}
}
从浏览器中访问该Servlet,可以看到通过类加载器读取的配置文件中的内容:
注意,这种方法只能是web资源放置在【src】目录中才可以使用,如果要读取的web资源是放置在web工程的目录下,使用类加载器也还是无法读取,因为类加载器只能读取类目录下的文件,这时候非Servlet类就无法读取资源文件,只能使用ServletContext来读取了。
方立勋老师说:“类加载器只能加载【classes】目录下的所有文件一次,这样在服务器运行web工程的过程中,如果我们修改【classes】目录下的student.properties配置文件,则由于类加载器不再加载,因此使用类加载器的方式不能读取修改后的内容”
但是我修改后,还是可以使用类加载器的方式读取classes】目录下修改后的student.properties配置文件,难道是因为JDK7的原因吗?
不过不管是什么原因,方立勋老师针对他的问题所采取的解决方案还是值得学习的,他采用先用类加载器获取该配置文件的路径,然后再采用传统方式获取这个文件的输入流。所以在Student中的getStudent()方法代码改为:
public class Student {
public void getStudent() throws IOException {
ClassLoader loader = Student.class.getClassLoader();
URL fileUrl = loader.getResource("student.properties");
String filePath = fileUrl.getPath(); FileInputStream fis = new FileInputStream(filePath);
Properties prop = new Properties();
prop.load(fis); String studentName = prop.getProperty("name");
String studentAge = prop.getProperty("age");
System.out.println(studentName+":"+studentAge);
}
}
这种方式还有一种好处就是,如果要读取的文件过大,而之前通过类加载器将大文件加载进内存就容易导致内存溢出,所以还是采用这种方式比较好。
最后再说明一点,如果是在非Servlet类中采用类加载器获取【classes】目录中的资源,方法参数的路径只需要是相对于【src】目录即可。
补充:使用类加载器加载【classes】目录中的资源,得到的路径取决是哪个虚拟机(或服务器)调用,例如上面的代码getStudent()方法,如果是在非Servlet的类的方法中被调用,那么就是使用JVM虚拟机,那么得到的资源路径并不是Tomcat的应用【webapps】目录的路径。因此如果是要为Servlet中提供资源,那么非Servlet类中获取资源的方法,请一定要使用Servlet来调用,这样才能保证得到的资源路径是在Tomcat服务器下的自己的web应用所在目录中的正确位置。
例如下面的例子,我的MyEclipse工作空间在【E】盘,而Tomcat服务器所在路径为【F】盘:
public class ResourceUtils { public static void main(String[] args) throws IOException {
getResource();
} @Test
public static void getResource() throws IOException { ClassLoader loader = ResourceUtils.class.getClassLoader();
URL url = loader.getResource("student.properties");
String path = url.getPath();
System.out.println(path);
}
}
而资源为student.properties配置文件,放置的位置为【src】目录下:
这个是在我的一个web应用中定义的一个非Servlet的普通Java类,这个类无论是用JUnit测试还是使用Main函数,亦或是使用别的非Servlet类来调用getResource方法获取在web应用下【src】目录中的student.properties资源,显示的路径为MyEclipse的工作空间,而不是Tomcat服务器:
而如果是使用Servlet来调用的话,才是真正显示在Tomcat中web应用所在的地方:
public class ServletDemo1 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { ResourceUtils.getResource();
}
}
因此在使用web工程中,如果使用非Servlet类来获取资源,请一定注意这个资源路径问题!!!
ServletContext对象中的getServletContextName()方法时返回的是在web.xml文件中使用<display-name>标签所设置的内容。使用这个标签可以为web应用设置一个名称,可以作用于路径的编写上(凡事不要都写死嘛╰( ̄▽ ̄)╭)。
Servlet的学习之ServletContext(2)的更多相关文章
- Servlet的学习之ServletContext(1)
本篇来介绍Servlet中非常重要的对象,如ServletConfig类和ServletContext类,尤其是ServletContext类中的一些方法,本篇先讲述一部分,在下一篇中继续补充. 在对 ...
- Servlet的学习之Cookie
从本篇开始学习Servlet技术中的Cookie专题. 首先来了解什么是“会话”.会话是web技术中的一个术语,可以简单的理解为:用户打开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭 ...
- Servlet的学习之Request请求对象(3)
本篇接上一篇,将Servlet中的HttpServletRequest对象获取RequestDispatcher对象后能进行的[转发]forward功能和[包含]include功能介绍完. 首先来看R ...
- Servlet的学习之Response响应对象(2)
本篇接上一篇<Servlet的学习之Response响应对象(1)>,继续从HttpServletResponse响应对象来介绍其方法和功能. 使用setHeader方法结合HTTP协议的 ...
- Servlet的学习之Response响应对象(1)
在之前学习了Servlet中的主体结构,包括Servlet的生命周期方法,和非生命周期方法能获取的一些非常重要的对象如ServletConfig.ServletContext对象等,而从这篇开始我们将 ...
- servlet入门学习之API
java servlet API学习网址: http://tomcat.apache.org/tomcat-7.0-doc/servletapi/ http://tomcat.apache.org/t ...
- Servlet基础学习
Servlet学习 Servlet是Server与Applet的缩写,是服务端小程序的意思.使用Java语言编写的服务器端程序,可以像生成动态的WEB页,Servlet主要运行在服务器端,并由服务器调 ...
- Servlet的学习之Filter过滤器技术(1)
本篇将讲诉Servlet中一项非常重要的技术,Filter过滤器技术.通过过滤器,可以对来自客户端的请求进行拦截,进行预处理或者对最终响应给客户端的数据进行处理后再输出. 要想使用Filter过滤器, ...
- Servlet的学习(四)
在本篇的Servlet的学习中,主要来学习由使用MyEclipse来开发Servlet的一些小细节. 细节一:在web.xml中可以对同一个Servlet配置多个对外访问路径,并如果在web.xml中 ...
随机推荐
- Python 模块续和面向对象的介绍(六)
一.基本模块 shutil 文件.目录.压缩包的处理模块 shutil.copyfile(src, dst) 拷贝文件 >>> shutil.copyfile('a.log','b. ...
- WPF中StringFormat 格式化 的用法
原文 WPF中StringFormat 格式化 的用法 网格用法 <my:DataGridTextColumn x:Name="PerformedDate" Header=& ...
- 11g的alert日志路径
一个测试库,11g,没有sys账户,无法用show parameter dump查看alert日志的路径,以前也碰到过,但后来就不了了之了.这次深挖下,也参考了下一些网上的帖子,于是找到了: $ORA ...
- hdu 1565&&hdu 1569 (最大点权独立集)
题目意思很明确就是选一些没有相连的数字,使和最大,建成二分图后求最大点权独立集,, #include<stdio.h> #include<string.h> const int ...
- test code
<?php abstract class Mediator{ abstract public function send($message, $colleague); } abstract cl ...
- 网络授时服务 NTP
NTP --- Network Time Protocol 网络授时服务,他解决的主要问题就是实现两台或者多台机器的时间同步问题,而传统的格林尼治时间不是标准的时间,因为地球自转的不是规则的. 网络 ...
- 12-UIKit(View绘制、绘制曲线、绘制文字、贴图)
目录: 1. View绘制 2. 绘制曲线 3. 绘制文字 4. 贴图 回到顶部 1. View绘制 1.1 做出自己的视图对象 TRCell : UITableViewCell : UIView U ...
- ie6背景透明的设置方法 ie6背景颜色透明和png图像透明解决方法
IE6浏览器,让我们又爱又恨.爱它的是,可以让我们写的代码的时候,可以更标准,恨的是,它有太多无厘头的IE6常见bug(详情点击),让我们焦头烂额.现在现在用百度浏览器调查,国内占有率不到6%了,但是 ...
- ModelAndView
我给你改一下public ModelAndView showDept(HttpServletRequest req,HttpServletResponse resp,ModelMap model){ ...
- Solr搜索结果说明
在admin页面,输入相关内容后,会返回xml格式的内容.说明如下: [html] view plaincopy <?xml version="1.0" encoding=& ...