Play生产模式下java.io.FileNotFoundException那点事

来源:互联网 时间:1970-01-01

之前”用Scala+Play构建地理数据查询接口”那篇文章里,用到的数据是json格式的文本文件area.json,存放在conf/jsons文件夹下。最开始是放在public/文件夹下,在线上准生产模式下运行:

activator dist

得到mosquito-1.0.zip压缩包,解压后:

去/bin目录下运行mosquito脚本报错:

java.io.FileNotFoundException

然后就去解压的mosquito-1.0/看发现并没有public文件夹,由此可见public文件夹在dist打包时被编译合并到其他文件夹下了(至于编译后具体在哪,需要看源码)。但是同时还发现conf/文件夹还存在,于是解决办法也简单,就将area.json放到conf/jsons,仔重新:

打包(activator dist) –> 解压 –> 运行(mosquito)

一切正常。

本以为这个事情到此就已经彻底解决了,然并卵。

之后写了“用Play实现文件上传与下载功能(超简单!)”,是直接在本地windows环境开发模式运行的,没有发现问题。之后将那个做了修改:上传图片后直接将图片显示到网页上。这个需求在发表文章时,在文章中插入图片并预览要用到。那么这个时候,就需要上传之后返回文件地址,通过routes中:

GET /assets/*file controllers.Assets.at(path="/public", file)

来访问,此时上传的文件夹在public/upload下,此时在开发模式下也完全没有问题。

但是想到上传文件放到public/下并不合理,如果public/下的css,image等静态文件比较多或者上传的文件多了的话也比较混乱,再者,放到public/下生产模式下根本无法运行成功。于是在项目根目录新建res文件夹,修改上传文件位置,此时文件可以上传到此,但是有出现新的问题:返回的文件地址通过“GET     /assets/*file”无法获取,http code 404.

通过查阅官方文档得知:

However, if you define two mappings for the Assets.at action, like this:

GET /javascripts/*file controllers.Assets.at(path="/public/javascripts", file)

GET /images/*file controllers.Assets.at(path="/public/images", file)

You will then need to specify both parameters when using the reverse router:

<script src="@routes.Assets.at("/public/javascripts", "jquery.js")"></script>

<image src="@routes.Assets.at("/public/images", "logo.png")">

于是改为:

GET /javascripts/*file controllers.Assets.at(path="/public", file)

GET /res/file controllers.Assets.at(path="/res",file)

此时要将:

<link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")">

改为:

<link rel="stylesheet" media="screen" href="@routes.Assets.at("public/stylesheets/main.css")">

这段代码中”@routes.Assets.at….”是反向路由,routes中配置了2个这个,所以需要给相对准确的路径,否则导致反向路由无法匹配成功。

这个时候运行,还是无法通过 GET /res  访问res/下的文件,不知为何。

在stackoverflow.com找到如下解决方法:

在controllers包下创建resourceCtrl并加入:

object resourceCtrl extends Controller{

val AbsolutePath = """^(/|[a-zA-Z]:\\).*""".r

def at(rootPath: String, file: String): Action[AnyContent] = Action { request =>

val fileUrlDeCode = java.net.URLDecoder.decode(file,"utf-8"); //中文需要URLDecoder

val fileToServe = rootPath match {

case AbsolutePath(_) => new File(rootPath, fileUrlDeCode)

case _ => new File(Play.application.getFile(rootPath), fileUrlDeCode)

}

if (fileToServe.exists) {

Ok.sendFile(fileToServe, inline = true)

} else {

Logger.error("Photos controller failed to serve photo: " + fileUrlDeCode)

NotFound

}

}

}

将之前的routes中GET /res  改为:

GET /resource/*file controllers.resourceCtrl.at(path="/",file)

运行一下,都ok,问题都解决(开发模式下)。

然后再生产模式下运行,通过routes中GET /res获取上传的文件,出错:

java.io.FileNotFoundException: D:\mosquito-project\mosquito\target\universal\mosquito-1.0\mosquito-1.0\bin\res (系统找不到指定的路径。)

搞了半天,又回到原点。

但是注意那个报错信息,是:mosquito-1.0\bin  ,这个地址是 Play.application.getFile获取的。这说明了什么?

这说明通过 Play.application(Play.current.path)获取到的path直接到项目根目录下的bin/文件夹下,而不是项目的根目录。

正确的地址应该是:

D:\mosquito-project\mosquito\target\universal\mosquito-1.0\mosquito-1.0\res

当是我把Play.application获取到的地址toString替换正确的时候,出现 “拒绝访问”。

但是我吧相同的程序放到linux上运行时,一切正常,一切正常,一切正常!  通过打印 Play.current.path 时,路径也正确是根目录。

而且,同时我也注意到:

windows上生产模式运行生成的logs文件夹在bin/下

linux上生产模式运行生成的logs文件夹在根目录下

这个我目前还不知道是为何,再研究研究。


相关阅读:
Top