This is an automated email from the ASF dual-hosted git repository. lukaszlenart pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/struts.git
commit 7574d9b31a84db4f93b9eac9c593f45aa6ecadd5 Author: Lukasz Lenart <[email protected]> AuthorDate: Fri Oct 23 13:16:25 2026 +0200 WW-5791 docs: document bind address, logging and packaging in boot-hello README: struts.boot.address, error pages, the jar name, BOM usage, a logging backend note, and non-Spring packaging alternatives. Spec: fix the .method(name) row and state that registry config is never broader than the equivalent struts.xml. Co-Authored-By: Claude Opus 5.5 <[email protected]> --- apps/boot-hello/README.md | 31 +++++++++++++++++++--- .../specs/2026-10-23-WW-5791-struts-boot-design.md | 8 ++++-- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/apps/boot-hello/README.md b/apps/boot-hello/README.md index 2e36a61cc..c0e048a4c 100644 --- a/apps/boot-hello/README.md +++ b/apps/boot-hello/README.md @@ -4,7 +4,9 @@ The smallest Struts Boot application: one action, one FreeMarker template, no `w ## Three steps -1. Depend on `org.apache.struts:struts2-boot-starter`. +1. Depend on `org.apache.struts:struts2-boot-starter`, at the same version as the rest of Struts. Importing + `org.apache.struts:struts2-bom` in `<dependencyManagement>` keeps the versions aligned so the starter needs no + `<version>` of its own. 2. Implement `StrutsBootApplication` and register actions: ```java @@ -32,6 +34,9 @@ mvn package -pl apps/boot-hello -am -DskipAssembly -DskipTests java -jar apps/boot-hello/target/struts2-boot-hello-<version>.jar --struts.boot.port=9090 ``` +`<version>` is the Struts version being built, for example `struts2-boot-hello-7.5.0-SNAPSHOT.jar`. The example is +not deployed to Maven repositories; build it from source. + ## Settings Settings are read from `struts.properties` on the classpath. A `--key=value` argument overrides the file. @@ -40,10 +45,12 @@ Settings are read from `struts.properties` on the classpath. A `--key=value` arg |----------------------------|---------|--------------------------------------------| | `struts.boot.port` | `8080` | HTTP port; `0` picks a free port | | `struts.boot.context-path` | `""` | Context path the application is served at | +| `struts.boot.address` | all | Interface to listen on, e.g. `127.0.0.1` | ## Defaults worth knowing -- Tomcat listens on all interfaces, not only on localhost. +- Tomcat listens on all interfaces, not only on localhost; set `struts.boot.address` to restrict it. +- Error pages show the status only, without stack traces or the Tomcat version. - `struts.devMode` stays off. - Each start uses a fresh temporary base directory (`struts-boot-<uuid>`) that is deleted on shutdown. - Views are FreeMarker only; a result path such as `hello.ftl` resolves to `/templates/hello.ftl` on the classpath. @@ -52,5 +59,21 @@ Settings are read from `struts.properties` on the classpath. A `--key=value` arg The jar is built with `maven-shade-plugin`. Every Struts plugin ships its own `META-INF/struts-plugin.xml`, and shading keeps only one file with that name, so with two or more plugins on the classpath all but one would be silently lost. -This example uses no plugins. If your application needs them, package it differently (for example with -Spring Boot's repackager or a `lib/` directory next to a thin jar) instead of shading. +This example uses no plugins. If your application needs them, package it differently instead of shading: a thin jar +with its dependencies in a `lib/` directory (`maven-dependency-plugin` copies them, `maven-jar-plugin` writes the +`Class-Path` manifest entry), or a distribution built with `maven-assembly-plugin`. + +## Logging + +Struts logs through the Log4j 2 API, and the starter ships no logging backend, so warnings and errors from Struts are +not printed. Add one to your application, for example (version managed by `org.apache.logging.log4j:log4j-bom`): + +```xml +<dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-core</artifactId> + <scope>runtime</scope> +</dependency> +``` + +with a `log4j2.xml` on the classpath, or `log4j-slf4j2-impl` to route to an SLF4J backend. diff --git a/docs/superpowers/specs/2026-10-23-WW-5791-struts-boot-design.md b/docs/superpowers/specs/2026-10-23-WW-5791-struts-boot-design.md index ea379b8e5..7cac1e787 100644 --- a/docs/superpowers/specs/2026-10-23-WW-5791-struts-boot-design.md +++ b/docs/superpowers/specs/2026-10-23-WW-5791-struts-boot-design.md @@ -44,7 +44,11 @@ self-contained jar is a later step. `ResultConfig` objects that `struts.xml` produces. Whatever a registered action does must match what the equivalent XML would do, including security defaults: strict method invocation, `@StrutsParameter` enforcement and the allowlist. If Boot quietly relaxes any of these to make - the first page easier, it has failed, even if it works. + the first page easier, it has failed, even if it works. The invariant: registry config is never + broader than the equivalent `struts.xml`. Where the two differ, the registry is narrower: a + registry action allows only its registered method, while an XML action also inherits the + package's global allowed methods (`execute,input,back,cancel,browse,save,delete,list,index` in + `struts-default`). - **A Spring Boot look-alike that pulls in Spring.** - **Core changes for Boot's convenience.** Boot uses only existing extension points (see "Wiring"). If something can't be done that way, stop and raise it. Don't patch `Dispatcher`. @@ -89,7 +93,7 @@ The template lives at `src/main/resources/templates/hello.ftl`. Running `HelloAp | top-level `actions.action(...)` | an action in a Boot-owned package with namespace `""` | | `namespace(ns, consumer)` | one `PackageConfig` with that namespace, extending `struts-default` | | `action(name, Class)` | `ActionConfig` with `className`; method defaults to `execute` | -| `.method(name)` | `methodName`, **and** adds it to the allowed methods. `struts-default` packages run with strict method invocation, so without this the call would be rejected | +| `.method(name)` | `methodName`, and adds it to the allowed methods. `ActionConfig#isAllowedMethod` already accepts the configured method, so the explicit entry only makes it visible in `getAllowedMethods()`. No other method is added: a registry action does not inherit the package's global allowed methods | | `.success(path)` | shorthand for `.result("success", path)` | | `.result(name, path)` | a `freemarker` result whose location is `/templates/` + `path` | | `.redirectAction(name, actionName)` | a `redirectAction` result |
