彻底解决java WEB项目的文件路径问题(war包)

在j2EE项目中,我们通常会把项目打包公布,通常是war包,作为独立单元,能够远程上传,载入,公布,还能够实现版本号控制,但这与我们开发过程中使用MyEclipse自己主动部署有所不同,下面做具体说明.

使用war包部署,在tomcat和WebLogic下部署有非常大的差别,tomcat会把war自己主动加压到当前文件夹下,然后再用解压的文件夹来公布,这与一般不会出现太大的意外,但假设是用WebLogic公布,就不会被解压,假设开发过程中不注意,war包公布后就有可能出现找不到文件的现象。比如:使用下面方法获取路径:

this.getClass().getClassLoader().getResource("/").getPath(); 

这与得到的是绝对Uri路径,比如::/D:/jboss-4.2.2.GA/server/default/deploy/hp.war/WEB-INF/classes/。带盘符的路径,显然在war中无法依据盘符来找到文件

另外一种方式:

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)方法。

也就是先得到上下文信息,然后通过以project文件夹为root的绝对路径。找到文件,举例说明:

InputStream is= context.getResourceAsStream(templatePath + "/" + templateFileName);
templatePath="/WEB-INF/classes/config/bctcms/"
templateFileName="source.xls"
能够看到templatePath是相对于context root 的路径,而不是相对于classes,这样即使文件在WEB-INF其它文件夹下。也能够顺利找到。经測试,对war的情况支持良好。

请来看看ServletContext.getResourceAsStreamAPI文档,
Returns a URL to the resource that is mapped to a specified path. The path must begin with a "/" and is interpreted as relative to the current context root. 
This method allows the servlet container to make a resource available to servlets from any source. Resources can be located on a local or remote file system, in a database, or in a .war file.

相信大家都看得懂。就不用赘述了。仅仅是有个问题,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”);

路径问题不要纠结太久,依据以上办法解决,最好都用ServletContext方法来获取。仅仅须要知道一种情况就能够了。达到目的才是最重要的。对吧?

有不正确之处,欢迎大家进行补充纠错!

update:当使用spring定时器时:request和servletContext就获取不到了,那么要使用这种办法直接获取ServletContext:

ContextLoader.getCurrentWebApplicationContext().getServletContext()

update20151228:

写文件的时候可能须要获得路径,比方上传文件的时候就须要输出流。而通过ServletContext不可以直接获得输出流的,但可以直接获取实际路径。如:

servletContext.getRealPath("/")

这样获得的路径是${context}/路径,再依据子路径和文件名称获取输出流。




posted @ 2017-07-06 08:15  zhchoutai  阅读(4553)  评论(0编辑  收藏  举报