This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch asf-site
in repository https://gitbox.apache.org/repos/asf/struts-site.git
The following commit(s) were added to refs/heads/asf-site by this push:
new 19ce02953 Automatic Site Publish by Buildbot
19ce02953 is described below
commit 19ce029530e07e0e92e3013d1a630e13e5ced53a
Author: buildbot <[email protected]>
AuthorDate: Mon Jul 6 13:35:17 2026 +0000
Automatic Site Publish by Buildbot
---
output/core-developers/default-properties.html | 6 +
output/core-developers/static-content.html | 82 +++++++
output/tag-developers/tag-reference.html | 2 +-
.../{tag-reference.html => webjar-tag.html} | 241 +++++----------------
4 files changed, 147 insertions(+), 184 deletions(-)
diff --git a/output/core-developers/default-properties.html
b/output/core-developers/default-properties.html
index 302bdfb72..148170a28 100644
--- a/output/core-developers/default-properties.html
+++ b/output/core-developers/default-properties.html
@@ -274,6 +274,12 @@ struts.ui.staticContentPath=/static
### headers)
struts.serve.static.browserCache=true
+### WebJars support
+### Master switch for resolving/serving WebJar assets under
<staticContentPath>/webjars/**
+struts.webjars.enabled=true
+### Optional comma-separated allowlist of WebJar names (empty = all WebJars on
the classpath)
+struts.webjars.allowlist=
+
### Set this to false if you wish to disable implicit dynamic method invocation
### via the URL request. This includes URLs like foo!bar.action, as well as
params
### like method:bar (but not action:foo).
diff --git a/output/core-developers/static-content.html
b/output/core-developers/static-content.html
index 3bc2cfcd9..52b180e0b 100644
--- a/output/core-developers/static-content.html
+++ b/output/core-developers/static-content.html
@@ -159,6 +159,12 @@
<li><a href="#custom-static-content-loaders"
id="markdown-toc-custom-static-content-loaders">Custom Static Content
Loaders</a></li>
<li><a href="#default-content-loader"
id="markdown-toc-default-content-loader">Default Content Loader</a></li>
<li><a href="#default-path" id="markdown-toc-default-path">Default
path</a></li>
+ <li><a href="#webjars-support" id="markdown-toc-webjars-support">WebJars
support</a> <ul>
+ <li><a href="#configuration"
id="markdown-toc-configuration">Configuration</a></li>
+ <li><a href="#security" id="markdown-toc-security">Security</a></li>
+ <li><a href="#customizing-resolution"
id="markdown-toc-customizing-resolution">Customizing resolution</a></li>
+ </ul>
+ </li>
<li><a href="#preventing-struts-from-handling-a-request"
id="markdown-toc-preventing-struts-from-handling-a-request">Preventing Struts
from handling a request</a></li>
</ul>
@@ -214,6 +220,82 @@ your static content to the web application directory, and
let the container hand
<p>This value is also used by the Default Content Loader.</p>
+<h2 id="webjars-support">WebJars support</h2>
+
+<p class="alert alert-info">Available since Struts 7.3.0.</p>
+
+<p><a href="https://www.webjars.org/">WebJars</a> package client-side
libraries (Bootstrap, jQuery, …) as JARs, shipping their assets
+under <code class="language-plaintext
highlighter-rouge">META-INF/resources/webjars/<name>/<version>/…</code>.
Instead of vendoring these files into your web application and
+re-committing them on every upgrade, you add the WebJar as a regular
dependency and let Struts resolve and serve it.</p>
+
+<p>Struts serves WebJar assets through the same static content pipeline
described above, under
+<code class="language-plaintext
highlighter-rouge"><staticContentPath>/webjars/**</code> (by default
<code class="language-plaintext highlighter-rouge">/static/webjars/**</code>).
Resolution is <strong>version-less</strong>: you reference a
+resource by its logical path and Struts resolves the version present on the
classpath. For example, a request for:</p>
+
+<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre
class="highlight"><code>/static/webjars/bootstrap/css/bootstrap.min.css
+</code></pre></div></div>
+
+<p>is served from <code class="language-plaintext
highlighter-rouge">META-INF/resources/webjars/bootstrap/5.3.8/css/bootstrap.min.css</code>
(whichever version is on the
+classpath). To emit these URLs from a template without hardcoding the version,
use the
+<a href="../tag-developers/webjar-tag">webjar tag</a>:</p>
+
+<div class="language-jsp highlighter-rouge"><div class="highlight"><pre
class="highlight"><code><span class="nt"><link</span> <span
class="na">rel=</span><span class="s">"stylesheet"</span> <span
class="na">href=</span><span class="s">"</span><span class="nt"><s:webjar
</span><span class="na">path=</span><span
class="s">"bootstrap/css/bootstrap.min.css"</span><span
class="nt">/></span><span class="s">"</span><span class="nt">/></span>
+</code></pre></div></div>
+
+<p>Struts resolves versions using <a
href="https://github.com/webjars/webjars-locator-lite">webjars-locator-lite</a>,
which is bundled
+with <code class="language-plaintext
highlighter-rouge">struts2-core</code>.</p>
+
+<h3 id="configuration">Configuration</h3>
+
+<table>
+ <thead>
+ <tr>
+ <th>Constant</th>
+ <th>Default</th>
+ <th>Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code class="language-plaintext
highlighter-rouge">struts.webjars.enabled</code></td>
+ <td><code class="language-plaintext highlighter-rouge">true</code></td>
+ <td>Master switch for resolving and serving WebJar assets under <code
class="language-plaintext
highlighter-rouge"><staticContentPath>/webjars/**</code>.</td>
+ </tr>
+ <tr>
+ <td><code class="language-plaintext
highlighter-rouge">struts.webjars.allowlist</code></td>
+ <td>(empty)</td>
+ <td>Optional comma-separated allowlist of WebJar names. When empty, all
WebJars on the classpath are allowed.</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>To restrict serving to specific WebJars:</p>
+
+<div class="language-xml highlighter-rouge"><div class="highlight"><pre
class="highlight"><code><span class="nt"><constant</span> <span
class="na">name=</span><span class="s">"struts.webjars.allowlist"</span> <span
class="na">value=</span><span class="s">"bootstrap,jquery"</span><span
class="nt">/></span>
+</code></pre></div></div>
+
+<p>To disable the feature entirely:</p>
+
+<div class="language-xml highlighter-rouge"><div class="highlight"><pre
class="highlight"><code><span class="nt"><constant</span> <span
class="na">name=</span><span class="s">"struts.webjars.enabled"</span> <span
class="na">value=</span><span class="s">"false"</span><span
class="nt">/></span>
+</code></pre></div></div>
+
+<h3 id="security">Security</h3>
+
+<p>Resolution is hard-constrained to the <code class="language-plaintext
highlighter-rouge">META-INF/resources/webjars/</code> root: path traversal
attempts (<code class="language-plaintext highlighter-rouge">..</code>, <code
class="language-plaintext highlighter-rouge">.</code>,
+backslashes) are rejected before resolution, the resolved path is re-checked
for containment, and only paths that the
+locator can resolve to a real WebJar are served. Disabled, unresolved,
traversal, and allowlist-blocked requests all
+<strong>fail closed</strong> - a <code class="language-plaintext
highlighter-rouge">404</code> when serving and empty output when building
URLs.</p>
+
+<h3 id="customizing-resolution">Customizing resolution</h3>
+
+<p>URL resolution is provided by the <code class="language-plaintext
highlighter-rouge">org.apache.struts2.webjars.WebJarUrlProvider</code>
container bean (default implementation
+<code class="language-plaintext
highlighter-rouge">DefaultWebJarUrlProvider</code>), which exposes <code
class="language-plaintext highlighter-rouge">resolveResourcePath(String)</code>
and <code class="language-plaintext highlighter-rouge">resolveUrl(String,
HttpServletRequest)</code>.
+Plugins and applications can replace it by declaring their own bean:</p>
+
+<div class="language-xml highlighter-rouge"><div class="highlight"><pre
class="highlight"><code><span class="nt"><bean</span> <span
class="na">type=</span><span
class="s">"org.apache.struts2.webjars.WebJarUrlProvider"</span> <span
class="na">class=</span><span
class="s">"com.example.MyWebJarUrlProvider"</span> <span
class="na">name=</span><span class="s">"myProvider"</span><span
class="nt">/></span>
+<span class="nt"><constant</span> <span class="na">name=</span><span
class="s">"struts.webjars.urlProvider"</span> <span
class="na">value=</span><span class="s">"myProvider"</span><span
class="nt">/></span>
+</code></pre></div></div>
+
<h2 id="preventing-struts-from-handling-a-request">Preventing Struts from
handling a request</h2>
<p>If there is a request that Struts is handling as an action, and you wish to
make Struts ignore it,
diff --git a/output/tag-developers/tag-reference.html
b/output/tag-developers/tag-reference.html
index 24734e6cb..1bd387602 100644
--- a/output/tag-developers/tag-reference.html
+++ b/output/tag-developers/tag-reference.html
@@ -203,7 +203,7 @@ additional URLs or action executions.</p>
<tr>
<td><a href="append-tag">append</a></td>
<td><a href="date-tag">date</a></td>
- <td> </td>
+ <td><a href="webjar-tag">webjar</a></td>
</tr>
<tr>
<td><a href="generator-tag">generator</a></td>
diff --git a/output/tag-developers/tag-reference.html
b/output/tag-developers/webjar-tag.html
similarity index 60%
copy from output/tag-developers/tag-reference.html
copy to output/tag-developers/webjar-tag.html
index 24734e6cb..3aacc17d5 100644
--- a/output/tag-developers/tag-reference.html
+++ b/output/tag-developers/webjar-tag.html
@@ -7,7 +7,7 @@
<meta http-equiv="Content-Language" content="en"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
- <title>Tag Reference</title>
+ <title>webjar tag</title>
<link href="/css/source-sans-pro.css" rel="stylesheet" type="text/css">
<link href="/css/font-awesome.css" rel="stylesheet">
@@ -148,213 +148,88 @@
<article class="container">
<section class="col-md-12">
- <a class="edit-on-gh"
href="https://github.com/apache/struts-site/edit/main/source/tag-developers/tag-reference.md"
title="Edit this page on GitHub">Edit on GitHub</a>
+ <a class="edit-on-gh"
href="https://github.com/apache/struts-site/edit/main/source/tag-developers/webjar-tag.md"
title="Edit this page on GitHub">Edit on GitHub</a>
- <a href="index" title="back to Tag Developers Guide"><< back to Tag
Developers Guide</a>
+ <a href="tag-reference.html" title="back to Tag Reference"><< back to Tag
Reference</a>
- <h1 class="no_toc" id="tag-reference">Tag Reference</h1>
+ <h1 id="webjar">webjar</h1>
-<ul id="markdown-toc">
- <li><a href="#generic-tags" id="markdown-toc-generic-tags">Generic
Tags</a></li>
- <li><a href="#ui-tag-reference" id="markdown-toc-ui-tag-reference">UI Tag
Reference</a></li>
-</ul>
+<p class="alert alert-info">Available since Struts 7.3.0.</p>
-<p>Generic tags are used for controlling the execution flow when the pages
render. These tags also allow for data
-extraction from places other than your action or the value stack, such as
<em>Localization</em> , JavaBeans, and including
-additional URLs or action executions.</p>
+<p>Please make sure you have read the <a href="tag-syntax">Tag Syntax</a>
document and understand how tag attribute syntax works.</p>
-<ul>
- <li>Control Tags provide control flow, such as <code
class="language-plaintext highlighter-rouge">if</code>, <code
class="language-plaintext highlighter-rouge">else</code>, and <code
class="language-plaintext highlighter-rouge">iterator</code></li>
- <li>Data Tags allow for data manipulation or creation, such as <code
class="language-plaintext highlighter-rouge">bean</code>, <code
class="language-plaintext highlighter-rouge">push</code>, and <code
class="language-plaintext highlighter-rouge">i18n</code></li>
-</ul>
+<h2 id="description">Description</h2>
-<blockquote>
- <p>Please make sure you have read the <a href="tag-syntax">Tag Syntax</a>
document and understand how tag attribute syntax works.</p>
-</blockquote>
+<p>Resolves a version-less <a href="https://www.webjars.org/">WebJar</a>
resource path to a servable URL and writes it to the output
+(or stores it in a variable when <code class="language-plaintext
highlighter-rouge">var</code> is set). For example, <code
class="language-plaintext
highlighter-rouge">bootstrap/css/bootstrap.min.css</code> is resolved to
+<code class="language-plaintext
highlighter-rouge"><ctx>/static/webjars/bootstrap/5.3.8/css/bootstrap.min.css</code>,
so you never hardcode the WebJar version in your templates.</p>
-<h2 id="generic-tags">Generic Tags</h2>
+<p>The tag emits a plain URL string, so it composes with <a
href="script-tag">script</a>, <a href="link-tag">link</a>, or a raw <code
class="language-plaintext highlighter-rouge"><link></code> /
+<code class="language-plaintext highlighter-rouge"><script></code>
element. See <a href="../core-developers/static-content#webjars-support">Static
Content</a> for the serving pipeline and
+configuration constants.</p>
-<p>Struts Generic Tags control the execution flow as pages render.</p>
+<p>Resolve a version-less WebJar resource path to a servable URL</p>
-<table>
- <thead>
- <tr>
- <th><strong>Control Tags</strong></th>
- <th><strong>Data Tags</strong></th>
- <th><strong>Other Tags</strong></th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td><a href="if-tag">if</a></td>
- <td><a href="a-tag">a</a></td>
- <td><a href="compress-tag">compress</a></td>
- </tr>
- <tr>
- <td><a href="elseif-tag">elseif</a></td>
- <td><a href="action-tag">action</a></td>
- <td><a href="script-tag">script</a></td>
- </tr>
- <tr>
- <td><a href="else-tag">else</a></td>
- <td><a href="bean-tag">bean</a></td>
- <td><a href="link-tag">link</a></td>
- </tr>
- <tr>
- <td><a href="append-tag">append</a></td>
- <td><a href="date-tag">date</a></td>
- <td> </td>
- </tr>
- <tr>
- <td><a href="generator-tag">generator</a></td>
- <td><a href="debug-tag">debug</a></td>
- <td> </td>
- </tr>
- <tr>
- <td><a href="iterator-tag">iterator</a></td>
- <td><a href="i18n-tag">i18n</a></td>
- <td> </td>
- </tr>
- <tr>
- <td><a href="merge-tag">merge</a></td>
- <td><a href="include-tag">include</a></td>
- <td> </td>
- </tr>
+<h2 id="attributes">Attributes</h2>
+
+<table class="tag-reference">
<tr>
- <td><a href="sort-tag">sort</a></td>
- <td><a href="param-tag">param</a></td>
- <td> </td>
+ <td colspan="6"><h4>Dynamic Attributes Allowed:</h4> false</td>
</tr>
<tr>
- <td><a href="subset-tag">subset</a></td>
- <td><a href="property-tag">property</a></td>
- <td> </td>
+ <td colspan="6"><hr /></td>
</tr>
<tr>
- <td> </td>
- <td><a href="push-tag">push</a></td>
- <td> </td>
+ <th class="tag-header"><h4>Name</h4></th>
+ <th class="tag-header"><h4>Required</h4></th>
+ <th class="tag-header"><h4>Default</h4></th>
+ <th class="tag-header"><h4>Evaluated</h4></th>
+ <th class="tag-header"><h4>Type</h4></th>
+ <th class="tag-header"><h4>Description</h4></th>
</tr>
<tr>
- <td> </td>
- <td><a href="set-tag">set</a></td>
- <td> </td>
+ <td class="tag-attribute">path</td>
+ <td class="tag-attribute"><strong>true</strong></td>
+ <td class="tag-attribute"></td>
+ <td class="tag-attribute">false</td>
+ <td class="tag-attribute">String</td>
+ <td class="tag-attribute">The version-less WebJar resource path, e.g.
bootstrap/css/bootstrap.min.css</td>
</tr>
<tr>
- <td> </td>
- <td><a href="text-tag">text</a></td>
- <td> </td>
+ <td class="tag-attribute">performClearTagStateForTagPoolingServers</td>
+ <td class="tag-attribute">false</td>
+ <td class="tag-attribute">false</td>
+ <td class="tag-attribute">false</td>
+ <td class="tag-attribute">Boolean</td>
+ <td class="tag-attribute">Whether to clear all tag state during
doEndTag() processing (if applicable)</td>
</tr>
<tr>
- <td> </td>
- <td><a href="url-tag">url</a></td>
- <td> </td>
+ <td class="tag-attribute">var</td>
+ <td class="tag-attribute">false</td>
+ <td class="tag-attribute"></td>
+ <td class="tag-attribute">false</td>
+ <td class="tag-attribute">String</td>
+ <td class="tag-attribute">Name used to reference the value pushed into
the Value Stack (scope: action).</td>
</tr>
- </tbody>
</table>
-<h2 id="ui-tag-reference">UI Tag Reference</h2>
+<h2 id="examples">Examples</h2>
-<p>Struts UI Tags display data in rich and reusable HTML.</p>
+<p><strong>Example 1</strong> - reference a WebJar stylesheet:</p>
-<table>
- <thead>
- <tr>
- <th><strong>Form Tags</strong></th>
- <th><strong>Non-Form UI Tags</strong></th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td><a href="checkbox-tag">checkbox</a></td>
- <td><a href="actionerror-tag">actionerror</a></td>
- </tr>
- <tr>
- <td><a href="checkboxlist-tag">checkboxlist</a></td>
- <td><a href="actionmessage-tag">actionmessage</a></td>
- </tr>
- <tr>
- <td><a href="combobox-tag">combobox</a></td>
- <td><a href="component-tag">component</a></td>
- </tr>
- <tr>
- <td><a href="datetextfield-tag">datetextfield</a></td>
- <td><a href="fielderror-tag">fielderror</a></td>
- </tr>
- <tr>
- <td><a href="doubleselect-tag">doubleselect</a></td>
- <td> </td>
- </tr>
- <tr>
- <td><a href="head-tag">head</a></td>
- <td> </td>
- </tr>
- <tr>
- <td><a href="file-tag">file</a></td>
- <td> </td>
- </tr>
- <tr>
- <td><a href="form-tag">form</a></td>
- <td> </td>
- </tr>
- <tr>
- <td><a href="hidden-tag">hidden</a></td>
- <td> </td>
- </tr>
- <tr>
- <td><a href="inputtransferselect-tag">inputtransferselect</a></td>
- <td> </td>
- </tr>
- <tr>
- <td><a href="label-tag">label</a></td>
- <td> </td>
- </tr>
- <tr>
- <td><a href="optiontransferselect-tag">optiontransferselect</a></td>
- <td> </td>
- </tr>
- <tr>
- <td><a href="optgroup-tag">optgroup</a></td>
- <td> </td>
- </tr>
- <tr>
- <td><a href="password-tag">password</a></td>
- <td> </td>
- </tr>
- <tr>
- <td><a href="radio-tag">radio</a></td>
- <td> </td>
- </tr>
- <tr>
- <td><a href="reset-tag">reset</a></td>
- <td> </td>
- </tr>
- <tr>
- <td><a href="select-tag">select</a></td>
- <td> </td>
- </tr>
- <tr>
- <td><a href="submit-tag">submit</a></td>
- <td> </td>
- </tr>
- <tr>
- <td><a href="textarea-tag">textarea</a></td>
- <td> </td>
- </tr>
- <tr>
- <td><a href="textfield-tag">textfield</a></td>
- <td> </td>
- </tr>
- <tr>
- <td><a href="token-tag">token</a></td>
- <td> </td>
- </tr>
- <tr>
- <td><a href="updownselect-tag">updownselect</a></td>
- <td> </td>
- </tr>
- </tbody>
-</table>
+<div class="language-jsp highlighter-rouge"><div class="highlight"><pre
class="highlight"><code><span class="nt"><link</span> <span
class="na">rel=</span><span class="s">"stylesheet"</span> <span
class="na">href=</span><span class="s">"</span><span class="nt"><s:webjar
</span><span class="na">path=</span><span
class="s">"bootstrap/css/bootstrap.min.css"</span><span
class="nt">/></span><span class="s">"</span><span class="nt">/></span>
+</code></pre></div></div>
+
+<p><strong>Example 2</strong> - reference a WebJar script:</p>
+
+<div class="language-jsp highlighter-rouge"><div class="highlight"><pre
class="highlight"><code><span class="nt"><s:webjar </span><span
class="na">var=</span><span class="s">"webjarUrl"</span><span class="na">
path=</span><span class="s">"jquery/jquery.min.js"</span><span
class="nt">/></span>
+<span class="nt"><s:script </span><span class="na">src=</span><span
class="s">"%{webjarUrl}"</span><span class="nt">/></span>
+</code></pre></div></div>
+
+<p><strong>Example 3</strong> - FreeMarker macro:</p>
+
+<div class="language-html highlighter-rouge"><div class="highlight"><pre
class="highlight"><code><span class="nt"><</span><span
class="err">@</span><span class="na">s.webjar</span> <span
class="na">path=</span><span class="s">"jquery/jquery.min.js"</span><span
class="nt">/></span>
+</code></pre></div></div>
</section>
</article>