在j2EE项目中,我们一般会把项目打包发布,一般是war包,作为独立单元,可以远程上传,加载,发布,还可以实现版本控制,但这与我们开发过程中使用MyEclipse自动部署有所不同,以下做详细说明.
使用war包部署,在tomcat和WebLogic下部署有很大的区别,tomcat会把war自动加压到当前目录下,然后再用解压的目录来发布,这与一般不会出现太大的意外,但如果是用WebLogic发布,就不会被解压,如果开发过程中不注意,war包发布后就有可能出现找不到文件的现象。例如:使用以下方法获取路径:
this.getClass().getClassLoader().getResource("/").getPath();
第二种方式:
this.getClass().getResource("/").getPath();
那么这样获取行不行呢?经试验,这与获取的是当前类的Uri目录,例如:/D:/jboss-4.2.2.GA/server/default/deploy/hp.war/WEB-INF/classes/com/jebel/helper/ 也是绝对路径,显然无法适用于war包。
其实以上两种方式都走入了岔路,因为读取文件未必要读取路径,文件操作一般都要转换为流的方式,既然要读取文件,不如直接读成输入流,也少了一步封装。请看以下方式:
InputStream is= this.getClass().getResourceAsStream("/config/bctcms/" + templateFileName);
意思是读取classes目录中,目录config/bctcms/下,文件名为templateFileName的文件输入流。经试验在war中可以正常读取到。
该方法存在一个弊端,只能读取classes目录下的文件,对于其他目录下的文件无能为力,显然并不适用于所有场景。
如果文件在WEB-INF目录下,如何进行读取呢?
答案是使用ServletContext.getResourceAsStream(String)方法。也就是先得到上下文信息,然后通过以工程目录为root的绝对路径,找到文件,举例说明:
InputStream is= context.getResourceAsStream(templatePath + "/" + templateFileName);
templatePath="/WEB-INF/classes/config/bctcms/"
templateFileName="source.xls"
可以看到templatePath是相对于context root 的路径,而不是相对于classes,这样即使文件在WEB-INF其他目录下,也可以顺利找到,经测试,对war的情况支持良好。请来看看
ServletContext.getResourceAsStream的
API文档,
相信大家都看得懂,就不用赘述了。只是有个问题,context是个什么东西?答案:ServletContext,上下文信息,在j2EE类中使用request获得,如:
ServletContext context = request.getSession().getServletContext();
那么在普通类中如何获取呢?暂时特别好的办法,使用application是一种方式,另外一种方式就是想办法先后去request对象,如:
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
HttpServletRequest request = ((ServletRequestAttributes) ra).getRequest();
this.context = request.getSession().getServletContext();
这样也是可以获得Context的
但如果是JSP中,可以直接这么获取输入流:
application.getResourceAsStream("xxx”);
有不对之处,欢迎大家进行补充纠错!
update:当使用spring定时器时:request和servletContext就获取不到了,那么要使用这样的办法直接获取ServletContext:
ContextLoader.getCurrentWebApplicationContext().getServletContext()
update20151228:
写文件的时候可能需要获得路径,比如上传文件的时候就需要输出流,而通过ServletContext不能够直接获得输出流的,但可以直接获取实际路径,如:
servletContext.getRealPath("/")