Автономное развертывание сервлета Scalatra
Я реализовал сервлет Scalatra и теперь хочу создать исполняемый файл jar, как описано в этом руководстве: http://www.scalatra.org/2.2/guides/deployment/standalone.html
Я использую IntelliJ IDEA с плагином Scala для разработки и sbt для сборки и запуска моего сервлета (я использовал sbt-idea для генерации файлов проекта). Моя проблема в том, что пакеты Jetty, которые использует JettyLauncher из учебного пособия, не могут быть найдены, когда я пытаюсь скомпилировать свой проект.
ОБНОВЛЕНИЕ: Используя ответ Мэтта, я смог скомпилировать и запустить JettyLauncher. Тем не менее, у меня все еще есть проблемы с sbt-сборкой ( https://github.com/sbt/sbt-assembly). Я следовал инструкции в файле readme, но при попытке выполнить задачу сборки получаю следующую ошибку:
[error] Not a valid command: assembly
[error] No such setting/task
[error] assembly
[error] ^
ОБНОВЛЕНИЕ 2: Благодаря Мэтту, у меня теперь есть рабочий build.scala, и я могу сгенерировать исполняемый файл jar, используя задачу сборки. Тем не менее, sbt-assembly не добавляет содержимое / src / main / webapp в jar. Я использую эту папку для хранения файлов HTML, CSS и JavaScript. Если Scalatra не может сопоставить маршрут, он обслуживает эти файлы, что работает при запуске сервлета с использованием container:start. Кроме того, я храню некоторые файлы, которые нужны серверу, в /src/main/webapp/WEB-INF. Эти файлы также не добавляются в банку.
Мой build.scala выглядит так:
import sbt._
import Keys._
import org.scalatra.sbt._
import org.scalatra.sbt.PluginKeys._
import com.mojolly.scalate.ScalatePlugin._
import ScalateKeys._
import sbtassembly.Plugin._
import AssemblyKeys._
object SketchlinkBuild extends Build {
val Organization = "de.foobar"
val Name = "Foobar"
val Version = "0.1"
val ScalaVersion = "2.10.0"
val ScalatraVersion = "2.2.0"
lazy val project = Project (
"foobar",
file("."),
settings = Defaults.defaultSettings ++ ScalatraPlugin.scalatraWithJRebel ++ scalateSettings ++ assemblySettings ++ Seq(
organization := Organization,
name := Name,
version := Version,
scalaVersion := ScalaVersion,
resolvers += Classpaths.typesafeReleases,
libraryDependencies ++= Seq(
"org.scalatra" %% "scalatra" % ScalatraVersion,
"org.scalatra" %% "scalatra-scalate" % ScalatraVersion,
"org.scalatra" %% "scalatra-specs2" % ScalatraVersion % "test",
"ch.qos.logback" % "logback-classic" % "1.0.6" % "runtime",
"org.eclipse.jetty" % "jetty-webapp" % "8.1.8.v20121106" % "compile;container",
"org.eclipse.jetty.orbit" % "javax.servlet" % "3.0.0.v201112011016" % "compile;container;provided;test" artifacts (Artifact("javax.servlet", "jar", "jar")),
/* Apache commons libraries */
"commons-codec" % "commons-codec" % "1.7",
"commons-io" % "commons-io" % "2.4",
/* JSON support */
"org.scalatra" %% "scalatra-json" % "2.2.1",
"org.json4s" %% "json4s-jackson" % "3.2.4",
/* thumbnail library */
"net.coobird" % "thumbnailator" % "0.4.3"
),
// ignore about.html in jars (needed for sbt-assembly)
mergeStrategy in assembly <<= (mergeStrategy in assembly) { (old) => {
case "about.html" => MergeStrategy.discard
case x => old(x) }
},
scalateTemplateConfig in Compile <<= (sourceDirectory in Compile){ base =>
Seq(
TemplateConfig(
base / "webapp" / "WEB-INF" / "templates",
Seq.empty, /* default imports should be added here */
Seq(
Binding("context", "_root_.org.scalatra.scalate.ScalatraRenderContext", importMembers = true, isImplicit = true)
), /* add extra bindings here */
Some("templates")
)
)
}
)
)
}
Заранее спасибо!
3 ответа
В настоящее время существует два варианта автономного развертывания:
- Единственный.jar, использующий sbt-сборку, которая содержит ресурсы среды выполнения и веб-приложения. Загрузка ресурсов из файла.jar довольно медленная в моем опыте.
- Распространение.zip файла с использованием
scalatra-sbt
плагин, содержит скрипт запуска оболочки, ресурсы времени выполнения и ресурсы веб-приложения в папках.
1. Автономный JAR
Для отдельного файла.jar, использующего sbt-assembly
вам нужно сначала добавить плагин project/build.sbt
:
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.9.0")
Затем вам нужно изменить сборку проекта, например project/build.scala
, Импортируйте настройки и ключи плагина:
import sbtassembly.Plugin._
import sbtassembly.Plugin.AssemblyKeys._
С этим вы можете создать настройки для sbt-assembly
плагин:
// settings for sbt-assembly plugin
val myAssemblySettings = assemblySettings ++ Seq(
// handle conflicts during assembly task
mergeStrategy in assembly <<= (mergeStrategy in assembly) {
(old) => {
case "about.html" => MergeStrategy.first
case x => old(x)
}
},
// copy web resources to /webapp folder
resourceGenerators in Compile <+= (resourceManaged, baseDirectory) map {
(managedBase, base) =>
val webappBase = base / "src" / "main" / "webapp"
for {
(from, to) <- webappBase ** "*" x rebase(webappBase, managedBase / "main" / "webapp")
} yield {
Sync.copy(from, to)
to
}
}
)
Первый определяет стратегию слияния, последний копирует статические веб-ресурсы из src/main/webapp
в <resourceManaged>/main/webapp
, Они будут включены в окончательный.jar в подпапке /webapp
,
Включите настройки в свой проект:
lazy val project = Project("myProj", file(".")).settings(mySettings: _*).settings(myAssemblySettings:_*)
Теперь лаунчер нужно создать. Обратите внимание, как установлена база ресурсов:
import org.eclipse.jetty.server.nio.SelectChannelConnector
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.webapp.WebAppContext
import org.scalatra.servlet.ScalatraListener
object JettyMain {
def run = {
val server = new Server
val connector = new SelectChannelConnector
connector.setPort(8080)
server.addConnector(connector)
val context = new WebAppContext
context.setContextPath("/")
val resourceBase = getClass.getClassLoader.getResource("webapp").toExternalForm
context.setResourceBase(resourceBase)
context.setEventListeners(Array(new ScalatraListener))
server.setHandler(context)
server.start
server.join
}
}
2. Распространение.zip с использованием scalatra-sbt
Plugin
Вам нужно добавить этот импорт в ваш SBT build.scala
:
import org.scalatra.sbt.DistPlugin._
import org.scalatra.sbt.DistPlugin.DistKeys._
Затем вам нужно добавить настройки плагина в ваш проект. Настройки находятся в DistPlugin.distSettings
,
Вы также можете настроить свой дистрибутив и добавить пользовательские настройки памяти, экспорт и параметры командной строки. Обратите внимание, что это все необязательно:
val myDistSettings = DistPlugin.distSettings ++ Seq(
mainClass in Dist := Some("ScalatraLauncher"),
memSetting in Dist := "2g",
permGenSetting in Dist := "256m",
envExports in Dist := Seq("LC_CTYPE=en_US.UTF-8", "LC_ALL=en_US.utf-8"),
javaOptions in Dist ++= Seq("-Xss4m", "-Dfile.encoding=UTF-8")
)
В командной строке SBT вы можете набрать dist
, Файл.zip будет в target
папка.
Я недавно столкнулся с проблемой, делая это.
Во-первых, вы должны убедиться, что пристань доступна во время компиляции. Эти две строки:
"org.eclipse.jetty" % "jetty-webapp" % "8.1.8.v20121106" % "container",
"org.eclipse.jetty.orbit" % "javax.servlet" % "3.0.0.v201112011016" % "container;provided;test" artifacts (Artifact("javax.servlet", "jar", "jar")),
Нужно иметь в них компиляцию:
"org.eclipse.jetty" % "jetty-webapp" % "8.1.8.v20121106" % "compile;container",
"org.eclipse.jetty.orbit" % "javax.servlet" % "3.0.0.v201112011016" % "compile;container;provided;test" artifacts (Artifact("javax.servlet", "jar", "jar"))
Во-вторых, из вашего описания звучит так, что sbt-сборка настроена неправильно. Вам необходимо удалить (закомментировать) эти строки:
lazy val buildSettings = Defaults.defaultSettings ++ Seq(
version := "0.1",
organization := "de.foobar",
scalaVersion := "2.10.1"
)
lazy val app = Project("app", file("app"),
settings = buildSettings ++ assemblySettings) settings(
// your settings here
)
Вам нужно будет добавить ++ assemblySettings
в ваш проект foobar сразу после scalateSettings
, Ваш файл plugins.sbt также должен содержать следующую строку:
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.9.0")
Для справки, я рекомендую не использовать sbt-assembly, потому что вы, скорее всего, столкнетесь с конфликтами зависимостей, которые необходимо будет решить с помощью стратегии слияния. Вместо этого я предлагаю вам использовать задачу, которая собирает ваши зависимости в каталог (примеры здесь и здесь). А затем добавить их в путь к классу Java с помощью java -cp /lib/* ...
,
В-третьих, будьте осторожны с проектом Jetty в GitHub Scalatra. Я использовал:
import java.net.InetSocketAddress
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.servlet.DefaultServlet
import org.scalatra.servlet.ScalatraListener
import org.eclipse.jetty.webapp.WebAppContext
object Jetty {
def main(args: Array[String]) = {
val socketAddress = new InetSocketAddress(8080)
val server = new Server(socketAddress)
val context = new WebAppContext()
context.setContextPath("/")
context.setResourceBase("src/main/webapp")
context.addEventListener(new ScalatraListener)
context.addServlet(classOf[DefaultServlet], "/")
server.setHandler(context)
server.start()
server.join()
}
}
Наконец, возможно, стоит проверить, что ваш ScalatraBootstrap находится в обычном месте.
Надеюсь, это поможет. Если нет, я могу опубликовать всю мою сборку.scala для вас.
Для получения актуального ответа, пожалуйста, обратитесь к этим двум файлам (Кредиты идут в Scalatra в книге действий):
а также
https://github.com/scalatra/scalatra-in-action/blob/master/chapter09-standalone/project/Build.scala