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 
&lt;staticContentPath&gt;/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/&lt;name&gt;/&lt;version&gt;/…</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">&lt;staticContentPath&gt;/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">&lt;link</span> <span 
class="na">rel=</span><span class="s">"stylesheet"</span> <span 
class="na">href=</span><span class="s">"</span><span class="nt">&lt;s:webjar 
</span><span class="na">path=</span><span 
class="s">"bootstrap/css/bootstrap.min.css"</span><span 
class="nt">/&gt;</span><span class="s">"</span><span class="nt">/&gt;</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">&lt;staticContentPath&gt;/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">&lt;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">/&gt;</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">&lt;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">/&gt;</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">&lt;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">/&gt;</span>
+<span class="nt">&lt;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">/&gt;</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">&lt;ctx&gt;/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">&lt;link&gt;</code> /
+<code class="language-plaintext highlighter-rouge">&lt;script&gt;</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">&lt;link</span> <span 
class="na">rel=</span><span class="s">"stylesheet"</span> <span 
class="na">href=</span><span class="s">"</span><span class="nt">&lt;s:webjar 
</span><span class="na">path=</span><span 
class="s">"bootstrap/css/bootstrap.min.css"</span><span 
class="nt">/&gt;</span><span class="s">"</span><span class="nt">/&gt;</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">&lt;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">/&gt;</span>
+<span class="nt">&lt;s:script </span><span class="na">src=</span><span 
class="s">"%{webjarUrl}"</span><span class="nt">/&gt;</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">&lt;</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">/&gt;</span>
+</code></pre></div></div>
 
   </section>
 </article>

Reply via email to