更改Scalatra和sbt默认目录

本文分享了在使用Scala和Scalatra框架开发Web项目时,如何调整默认目录结构以实现更符合业务需求的交互驱动设计(IDD)。作者详细介绍了修改sbt配置、Jetty启动类及模板配置的过程。

惯例并不总是很好。 我最近在Codurance开始了一个新的内部Web项目,我决定使用Scala。 因为我不喜欢大型框架,所以选择Scalatra作为微型Web框架。

第一个挑战是我想用不同的目录结构来组织我的应用程序。 默认情况下, sbt和Scalatra使用与maven相同的约定:

> /src/main/scala       // source code
> /src/main/resources   // production resources
> /scr/test/scala       // tests
> /scr/test/resouces    // test resources

在过去的几年中,我一直在为项目尝试不同的目录结构。 在解释业务领域时,我希望我的目录更加有意义。 新的目录结构是我所谓的交互驱动设计(IDD)的一部分 ,有关其完整说明,请参见我们的视频区域 。 在该演讲中,我将详细介绍新目录结构背后的原理。

我想用于这个新项目的目录结构是:

> /src/core/scala          // source code for my core domain
> /src/core-test/scala     // tests for my core domain

> /src/data/resources      // resources for data migration and test data
> /src/data/scala          // code for data migration and test data

> /src/web/resources       // delivery mechanism resources
> /src/web/scala           // delivery mechanism code (controllers, API, etc)
> /src/web/webapp          // web files (WEB-INF folder, css, javascript, Jade templates, etc)
> /src/web-test/scala      // tests for my delivery mechanism

同样,如果您观看“ 交互驱动设计”(IDD)演讲 ,则上面的目录结构将更有意义。

最大的挑战是将默认目录main重命名为web 。 那破坏了整个世界。 这是我必须修复的所有更改:

build.sbt

unmanagedSourceDirectories in Compile := Seq((baseDirectory.value / "src/core/scala"),
                                             (baseDirectory.value / "src/data/scala"),
                                             (baseDirectory.value / "src/web/scala"))

unmanagedResourceDirectories in Compile += baseDirectory.value / "src/data/resources"

unmanagedSourceDirectories in Test := Seq((baseDirectory.value / "src/core-test/scala"),
                                          (baseDirectory.value / "src/web-test/scala"))

webappSrc in webapp <<= (baseDirectory in Compile) map { _ / "src/web/webapp" }

webappDest in webapp <<= (baseDirectory in Compile) map { _ / "src/web/webapp" }

最后两行需要用到webappSrcwebappDest ,因为我还使用了一个手动启动Jetty的类,该类将Scalatra侦听器钩住。

码头工人

import org.eclipse.jetty.server.Server
import org.eclipse.jetty.servlet.DefaultServlet
import org.eclipse.jetty.webapp.WebAppContext
import org.scalatra.servlet.ScalatraListener

object JettyLauncher {

    def main(args: Array[String]) {
        val port = if(System.getenv("PORT") != null) System.getenv("PORT").toInt else 8089

        val server = new Server(port)
        val context = new WebAppContext()
        context.setClassLoader(JettyLauncher.getClass.getClassLoader)
        context setContextPath "/"
        context.setResourceBase("src/web/webapp")
        context.addEventListener(new ScalatraListener)
        context.addServlet(classOf[DefaultServlet], "/")

        server.setHandler(context)

        server.start
        server.join
    }
}

执行此类时,找不到ScalatraBootstrap ,这就是为什么我必须在JettyLauncher中添加以下行:

> context.setClassLoader(JettyLauncher.getClass.getClassLoader)

Scalatra依靠默认目录main来找到ScalatraBootstrap ,这就是我设法确保可以找到ScalatraBootstrap的方式。

请注意,我还必须更改资源库,指向Web文件夹而不是main

> context.setResourceBase("src/web/webapp")

因为我用通过模板Scalate的 ,我不得不改变对build.scala Scalate的模板配置。

build.scala

object MonitorBuild extends Build {
    val Organization = "com.codurance"
    val Name = "monitor"
    val Version = "0.1.0-SNAPSHOT"
    val ScalaVersion = "2.11.6"
    val ScalatraVersion = "2.4.0.RC1"

    lazy val project = Project(
        "monitor",
        file("."),
        settings = ScalatraPlugin.scalatraSettings ++ scalateSettings ++ Seq(

            // dependencies and some other stuff here

            scalateTemplateConfig in Compile <<= (sourceDirectory in Compile) { base =>
                Seq(
                    TemplateConfig(
                        new RichFile(new File("src")) / "web" / "webapp" / "WEB-INF" / "templates",
                        Seq.empty, 
                        Seq(
                            Binding("context", "_root_.org.scalatra.scalate.ScalatraRenderContext", importMembers = true, isImplicit = true)
                        ), 
                        Some("templates")
                    )
                )
            }
        )
    )
}

上面重要的一行是:

> new RichFile(new File("src")) / "web" / "webapp" / "WEB-INF" / "templates"

这使Scalate在Web目录中而不是main中找到模板。

确保在plugins.sbt中有这些行

> addSbtPlugin("com.mojolly.scalate" % "xsbt-scalate-generator" % "0.5.0")
>
> addSbtPlugin("org.scalatra.sbt" % "scalatra-sbt" % "0.4.0")

我不需要在web.xmlScalatraBootstrap上进行任何更改。

上述配置使我可以通过以下方式运行应用程序

> ./sbt container:start

这就是我通常在本地运行应用程序的方式,还允许我创建一个胖jar文件并执行JettyLauncher类,这就是我在生产环境中运行的方式:

> java -cp <myapplication>.jar com.codurance.JettyLauncher

胖子jar文件是通过以下方式创建的:

> ./sbt assembly

这是IntelliJ IDEA上折叠目录结构的外观:

2015-11-21-文件夹结构崩溃

这是展开后的样子:

2015-11-21-folder-structure-expanded

尽管花了我一段时间才能弄清所有这些,但我很高兴能够以对我们有意义的方式来组织我的项目。

翻译自: https://www.javacodegeeks.com/2015/11/changing-scalatra-sbt-default-directories.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值