https://github.com/earldouglas/sbt-war
Package and run WAR files from sbt
https://github.com/earldouglas/sbt-war
j2ee sbt sbt-plugin servlet war
Last synced: 5 months ago
JSON representation
Package and run WAR files from sbt
- Host: GitHub
- URL: https://github.com/earldouglas/sbt-war
- Owner: earldouglas
- License: bsd-3-clause
- Created: 2011-04-24T10:27:46.000Z (over 14 years ago)
- Default Branch: main
- Last Pushed: 2025-05-01T21:26:34.000Z (6 months ago)
- Last Synced: 2025-05-06T10:09:46.505Z (6 months ago)
- Topics: j2ee, sbt, sbt-plugin, servlet, war
- Language: Scala
- Homepage:
- Size: 1.83 MB
- Stars: 382
- Watchers: 18
- Forks: 102
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
[](https://github.com/earldouglas/sbt-war/actions/workflows/build.yml)
[](https://github.com/earldouglas/sbt-war/tags)
[](https://repo1.maven.org/maven2/com/earldouglas/sbt-war_2.12_1.0/)# sbt-war
sbt-war is an [sbt](https://www.scala-sbt.org/) plugin for packaging and
running WAR files.sbt-war is formerly known as xsbt-web-plugin. For documentation and
source code of prior versions, browse this repository from the desired
git tag. The most recent prior version is
[4.2.5](https://github.com/earldouglas/sbt-war/tree/4.2.5).## Requirements
* sbt 1.x and up
* Scala 2.12.x and up## Getting help
* Submit a question, bug report, or feature request as a [new GitHub
issue](https://github.com/earldouglas/sbt-war/issues/new)
* Look for *earldouglas* in the `#sbt` channel on the [Scala Discord
server](https://discord.com/invite/scala)## Project structure
A project that uses sbt-war looks something like this:
```
$ tree my-web-project/
my-web-project/
├── build.sbt
├── project
│ ├── build.properties
│ └── plugins.sbt
└── src
├── main
│ ├── scala
│ │ └── mypackage
│ │ └── MyServlet.scala
│ └── webapp
│ ├── images
│ │ └── logo.png
│ ├── index.html
│ └── styles
│ └── style.css
└── test
└── scala
├── http.scala
└── mypackage
└── MyServletSuite.scala
```A packaged WAR file looks something like this:
```
$ sbt "show package"
[info] /path/to/my-web-project/target/scala-3.1.0/my-web-project_3-0.1.0-SNAPSHOT.war$ jar -tf target/scala-3.1.0/my-web-project_3-0.1.0-SNAPSHOT.war | LC_COLLATE=C sort
META-INF/MANIFEST.MF
WEB-INF/
WEB-INF/classes/
WEB-INF/classes/mypackage/
WEB-INF/classes/mypackage/Servlet.class
WEB-INF/classes/mypackage/Servlet.tasty
WEB-INF/lib/
WEB-INF/lib/scala-library-2.13.6.jar
WEB-INF/lib/scala3-library_3-3.1.0.jar
images/
images/logo.png
index.html
styles/
styles/style.css
```Classes under *src/main/scala* are compiled and included in the WAR
file under *WEB-INF/classes*.Dependencies are copied as JAR files into the *WEB-INF/lib/* directory.
Static assets (such as .html files, stylesheets, images, etc.) are
copied from *src/main/webapp* to to the root of the WAR file.## Getting started from a template
```
$ sbt new earldouglas/sbt-war.g8name [My Web Project]: hello sbt-war
Template applied in ./hello-sbt-war
$ cd hello-sbt-war/
$ sbt
> warStart
``````
$ curl localhost:8080/helloHello, world!
``````
> warStop
```## Getting started from scratch
Create a new empty project:
```
$ mkdir myproject
$ cd myproject
```Set up the project structure:
```
$ mkdir project
$ mkdir -p src/main/scala/mypackage
```Configure sbt:
*project/build.properties:*
```
sbt.version=1.10.2
```*project/plugins.sbt:*
```scala
addSbtPlugin("com.earldouglas" % "sbt-war" % "5.0.0")
```*build.sbt:*
```scala
scalaVersion := "3.5.1"
enablePlugins(SbtWar)
```Add a servlet:
*src/main/scala/mypackage/MyServlet.scala*:
```scala
package mypackageimport jakarta.servlet.annotation.WebServlet
import jakarta.servlet.http.HttpServlet
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse@WebServlet(urlPatterns = Array("/hello"))
class MyServlet extends HttpServlet:
override def doGet(
req: HttpServletRequest,
res: HttpServletResponse
): Unit =
res.setContentType("text/html")
res.setCharacterEncoding("UTF-8")
res.getWriter.write("""Hello, world!
""")
```Run it from sbt with `warStart`:
```
$ sbt
> warStart
``````
$ curl localhost:8080/helloHello, world!
```Stop it with `warStop`:
```
> warStop
```Create a WAR file with `package`:
```
> package
```## Settings
| Key | Type | Default | Notes |
| ------------------ | ------------------ | ------------------ | --------------------------------------------------------------------------- |
| `warResources` | `Map[String,File]` | *src/main/webapp* | Static files (HTML, CSS, JS, images, etc.) to serve directly |
| `warClasses` | `Map[String,File]` | project classes | .class files to copy into the *WEB-INF/classes* directory |
| `warLib` | `Map[String,File]` | project libs | JAR files to copy into the *WEB-INF/lib* directory |
| `warPort` | `Int` | `8080` | The local container port to use when running with `warStart` |
| `warForkOptions` | [`ForkOptions`][1] | [`forkOptions`][2] | Options for the forked JVM used when running with `warStart` |## Commands
| Key | Notes |
| ----------------- | ----------------------------------------------------------------------- |
| `warStart` | Starts a local container, serving content directly from project sources |
| `warStartPackage` | Starts a local container, serving content from the packaged WAR file |
| `warJoin` | Blocks until the container shuts down |
| `warStop` | Shuts down the container |### `warResources`
Resources are the various static files, deployment descriptors, etc.
that go into a WAR file.The `warResources` setting is a mapping from destination to source of
these files. The destination is a path relative to the contents of the
WAR file. The source is a path on the local filesystem.By default, everything in *src/main/webapp* is included.
For example, given the following WAR file:
```
myproject.war
├── index.html
├── styles/
│ └── theme.css
├── WEB-INF/
│ └── web.xml
└── META-INF/
└── MANIFEST.MF
```The `warResources` mapping would look like this:
```
"index.html" -> File(".../src/main/webapp/index.html")
"styles/theme.css" -> File(".../src/main/webapp/styles/theme.css")
"WEB-INF/web.xml" -> File(".../src/main/webapp/WEB-INF/web.xml")
```To use a different directory, e.g. *src/main/WebContent*:
```scala
warResources :=
(Compile / sourceDirectory)
.map(_ / "WebContent")
.map(WebappComponents.getResources)
```Manifest attributes of the WAR file can be configured via
`packageOptions`:```scala
sbt.Keys.`package` / packageOptions +=
Package.ManifestAttributes(
java.util.jar.Attributes.Name.SEALED -> "true"
)
```### `warClasses`
By default, project classes are copied into the *WEB-INF/classes*
directory of the WAR file. To package them in a JAR file in the
*WEB-INF/lib* directory instead, set `exportJars`:```scala
exportJars := true
```See ["Configure
packaging"](https://www.scala-sbt.org/1.x/docs/Howto-Package.html) in
the sbt documentation for additional information.### `warLib`
By default, all runtime dependencies are copied into the *WEB-INF/lib*
directory.To use a dependency at compile time but exclude it from the WAR file,
set its scope to `Provided`:```scala
libraryDependencies += "foo" % "bar" % "1.0.0" % Provided
```### `warPort`
By default, the container runs on port *8080*. To use a different port,
set `warPort`:```scala
warPort := 9090
```### `warForkOptions`
To set environment variables, system properties, and more for the
forked container JVM, set a
[ForkOptions](https://www.scala-sbt.org/1.x/api/sbt/ForkOptions.html)
instance via `warForkOptions`.For example: to be able to attach a debugger, set `-Xdebug` and
`-Xrunjdwp`:*build.sbt:*
```scala
warForkOptions :=
ForkOptions()
.withRunJVMOptions(
Seq(
"-Xdebug",
"-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000"
)
)
```### `warStart` and `warStartPackage`
To run the webapp directly from project sources, use `warStart`:
```
> warStart
```To run the webapp from the packaged WAR file, use `warStartPackage`:
```
> warStartPackage
```Both of these can be used with [triggered
execution](https://www.scala-sbt.org/1.x/docs/Triggered-Execution.html)
to automatically restart the container when source code is modified:```
> ~ warStart
```[Container logs](https://www.scala-sbt.org/1.x/docs/Howto-Logging.html)
will appear both in the console and under the `target/streams/`.### `warJoin`
To block sbt while the container is running, use `warJoin`:
```
$ sbt warStart warJoin
```This is useful for running sbt in production (e.g. in a Docker
container), if you're into that kind of thing.### `warStop`
To stop the running container, use `warStop`:
```
> warStop
```[1]: https://www.scala-sbt.org/1.x/api/sbt/ForkOptions.html
[2]: https://www.scala-sbt.org/1.x/api/sbt/Keys$.html#forkOptions:sbt.TaskKey[sbt.ForkOptions]