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 f5a440942fb665f0971056262b3aa4d1acff4bf9 Author: Lukasz Lenart <[email protected]> AuthorDate: Fri Oct 23 12:59:54 2026 +0200 WW-5791 feat(boot): add boot-hello example app with runnable jar Co-Authored-By: Claude Opus 5.5 <[email protected]> --- apps/boot-hello/README.md | 56 ++++++++++++++ apps/boot-hello/pom.xml | 90 ++++++++++++++++++++++ .../org/apache/struts2/boot/hello/HelloAction.java | 30 ++++++++ .../org/apache/struts2/boot/hello/HelloApp.java | 35 +++++++++ .../src/main/resources/templates/hello.ftl | 21 +++++ .../apache/struts2/boot/hello/HelloAppTest.java | 45 +++++++++++ apps/pom.xml | 1 + boot/src/test/resources/templates/admin/users.ftl | 20 +++++ boot/src/test/resources/templates/hello.ftl | 20 +++++ 9 files changed, 318 insertions(+) diff --git a/apps/boot-hello/README.md b/apps/boot-hello/README.md new file mode 100644 index 000000000..2e36a61cc --- /dev/null +++ b/apps/boot-hello/README.md @@ -0,0 +1,56 @@ +# Struts Boot Hello + +The smallest Struts Boot application: one action, one FreeMarker template, no `web.xml`, no `struts.xml`. + +## Three steps + +1. Depend on `org.apache.struts:struts2-boot-starter`. +2. Implement `StrutsBootApplication` and register actions: + + ```java + public class HelloApp implements StrutsBootApplication { + + public static void main(String[] args) { + StrutsBoot.run(HelloApp.class, args); + } + + @Override + public void actions(ActionRegistry actions) { + actions.action("hello", HelloAction.class).success("hello.ftl"); + } + } + ``` + +3. Put the view in `src/main/resources/templates/hello.ftl` and run `main()`. + +Then open http://localhost:8080/hello.action. + +## Running the jar + +``` +mvn package -pl apps/boot-hello -am -DskipAssembly -DskipTests +java -jar apps/boot-hello/target/struts2-boot-hello-<version>.jar --struts.boot.port=9090 +``` + +## Settings + +Settings are read from `struts.properties` on the classpath. A `--key=value` argument overrides the file. + +| Key | Default | Meaning | +|----------------------------|---------|--------------------------------------------| +| `struts.boot.port` | `8080` | HTTP port; `0` picks a free port | +| `struts.boot.context-path` | `""` | Context path the application is served at | + +## Defaults worth knowing + +- Tomcat listens on all interfaces, not only on localhost. +- `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. + +## Shading and plugins + +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. diff --git a/apps/boot-hello/pom.xml b/apps/boot-hello/pom.xml new file mode 100644 index 000000000..d6b043b6d --- /dev/null +++ b/apps/boot-hello/pom.xml @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.struts</groupId> + <artifactId>struts2-apps</artifactId> + <version>7.5.0-SNAPSHOT</version> + </parent> + + <artifactId>struts2-boot-hello</artifactId> + <packaging>jar</packaging> + <version>7.5.0-SNAPSHOT</version> + <name>Struts 2 Boot Hello</name> + <description>Struts Boot example application packaged as a runnable jar</description> + + <dependencies> + <dependency> + <groupId>org.apache.struts</groupId> + <artifactId>struts2-boot-starter</artifactId> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <finalName>${project.artifactId}-${project.version}</finalName> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-shade-plugin</artifactId> + <version>3.6.0</version> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>shade</goal> + </goals> + <configuration> + <createDependencyReducedPom>false</createDependencyReducedPom> + <transformers> + <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> + <mainClass>org.apache.struts2.boot.hello.HelloApp</mainClass> + </transformer> + <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> + </transformers> + <filters> + <filter> + <artifact>*:*</artifact> + <excludes> + <exclude>META-INF/*.SF</exclude> + <exclude>META-INF/*.DSA</exclude> + <exclude>META-INF/*.RSA</exclude> + </excludes> + </filter> + </filters> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/apps/boot-hello/src/main/java/org/apache/struts2/boot/hello/HelloAction.java b/apps/boot-hello/src/main/java/org/apache/struts2/boot/hello/HelloAction.java new file mode 100644 index 000000000..6dea4336d --- /dev/null +++ b/apps/boot-hello/src/main/java/org/apache/struts2/boot/hello/HelloAction.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.struts2.boot.hello; + +public class HelloAction { + + public String execute() { + return "success"; + } + + public String getMessage() { + return "Hello from Struts Boot"; + } +} diff --git a/apps/boot-hello/src/main/java/org/apache/struts2/boot/hello/HelloApp.java b/apps/boot-hello/src/main/java/org/apache/struts2/boot/hello/HelloApp.java new file mode 100644 index 000000000..7c47054ae --- /dev/null +++ b/apps/boot-hello/src/main/java/org/apache/struts2/boot/hello/HelloApp.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.struts2.boot.hello; + +import org.apache.struts2.boot.ActionRegistry; +import org.apache.struts2.boot.StrutsBoot; +import org.apache.struts2.boot.StrutsBootApplication; + +public class HelloApp implements StrutsBootApplication { + + public static void main(String[] args) { + StrutsBoot.run(HelloApp.class, args); + } + + @Override + public void actions(ActionRegistry actions) { + actions.action("hello", HelloAction.class).success("hello.ftl"); + } +} diff --git a/apps/boot-hello/src/main/resources/templates/hello.ftl b/apps/boot-hello/src/main/resources/templates/hello.ftl new file mode 100644 index 000000000..be6490fc2 --- /dev/null +++ b/apps/boot-hello/src/main/resources/templates/hello.ftl @@ -0,0 +1,21 @@ +<#-- +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +--> +<h1><@s.property value="message"/></h1> diff --git a/apps/boot-hello/src/test/java/org/apache/struts2/boot/hello/HelloAppTest.java b/apps/boot-hello/src/test/java/org/apache/struts2/boot/hello/HelloAppTest.java new file mode 100644 index 000000000..ba9881a2b --- /dev/null +++ b/apps/boot-hello/src/test/java/org/apache/struts2/boot/hello/HelloAppTest.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.struts2.boot.hello; + +import org.apache.struts2.boot.StrutsBoot; +import org.apache.struts2.boot.StrutsBootServer; +import org.junit.Test; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; + +import static org.assertj.core.api.Assertions.assertThat; + +public class HelloAppTest { + + @Test + public void testHelloPageRenders() throws Exception { + try (StrutsBootServer server = StrutsBoot.start(HelloApp.class, "--struts.boot.port=0")) { + HttpRequest request = HttpRequest.newBuilder(URI.create(server.baseUrl() + "/hello.action")).GET().build(); + + HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()); + + assertThat(response.statusCode()).isEqualTo(200); + assertThat(response.body()).contains("Hello from Struts Boot"); + } + } +} diff --git a/apps/pom.xml b/apps/pom.xml index 9ff432498..866c4b5ef 100644 --- a/apps/pom.xml +++ b/apps/pom.xml @@ -33,6 +33,7 @@ <modules> <module>showcase</module> <module>rest-showcase</module> + <module>boot-hello</module> </modules> <properties> diff --git a/boot/src/test/resources/templates/admin/users.ftl b/boot/src/test/resources/templates/admin/users.ftl index e9544fbee..1d2feeff8 100644 --- a/boot/src/test/resources/templates/admin/users.ftl +++ b/boot/src/test/resources/templates/admin/users.ftl @@ -1 +1,21 @@ +<#-- +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +--> <h1>users</h1> diff --git a/boot/src/test/resources/templates/hello.ftl b/boot/src/test/resources/templates/hello.ftl index 102b1e4a4..be6490fc2 100644 --- a/boot/src/test/resources/templates/hello.ftl +++ b/boot/src/test/resources/templates/hello.ftl @@ -1 +1,21 @@ +<#-- +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +--> <h1><@s.property value="message"/></h1>
