之前”用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文件夹在根目录下
这个我目前还不知道是为何,再研究研究。