blob: 1416472aece6a9a7592613cd276c23c507ff2397 [file] [view]
---
layout: default
title: Static Content
parent:
title: Core Developers
url: index
---
# Static Content
{:.no_toc}
* Will be replaced with the ToC, excluding a header
{:toc}
Struts can serve a static content like CSS and JavaScript files using a predefined path. By default, these resources
are served using `/static` path defined using a constant `struts.ui.staticContentPath` - see below for more details.
Please remember to include this path in your filter mapping if you use a custom mapping, see [web.xml](web-xml.md) example config.
## Disabling static content
You can disable this feature by setting the following constant to `false`. Once disabled you must provided the required
CSS & JavaScript files on your own, which can be a good thing when you want to use a CDN.
```xml
<constant name="struts.serve.static" value="false"/>
```
> If you disable this feature, but you use the `xhtml`, or `css_xhtml` theme, make sure the JavasScript and CSS files
> shipped inside the core jar are extracted to your web application directory or served in some other way.
## Custom Static Content Loaders
Static content is served by an implementation of `org.apache.struts2.dispatcher.StaticContentLoader`. To write your own
`StaticContentLoader`, implement `StaticContentLoader` and define a bean for the class:
```xml
<bean type="org.apache.struts2.dispatcher.StaticContentLoader" class="MyStaticContentLoader" name="myLoader"/>
<constant name="struts.staticContentLoader" value="myLoader"/>
```
## Default Content Loader
The Apache Struts provides a default implementation of `StaticContentLoader` which
is `org.apache.struts2.dispatcher.DefaultStaticContentLoader`. This loader will handle urls that start with "/static/"
by default.
This content loader can serve static content from the classpath, so when writing a plugin, you can put a file inside
your plugin's jar like "/static/image/banner.jpg" and it will be served when the url "/static/image/banner.jpg" is
requested.
> This loader is not optimized to handle static content, and to improve performance, it is recommended that you extract
> your static content to the web application directory, and let the container handle them.
## Default path
If needed you can change the default path at which static content is served. Just define a new `constant` in your
`struts.xml` with a path as below:
```xml
<constant name="struts.ui.staticContentPath" value="/my-static-content"/>
```
This value is also used by the Default Content Loader.
## WebJars support
{:.alert .alert-info}
Available since Struts 7.3.0.
[WebJars](https://www.webjars.org/) package client-side libraries (Bootstrap, jQuery, …) as JARs, shipping their assets
under `META-INF/resources/webjars/<name>/<version>/…`. 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.
Struts serves WebJar assets through the same static content pipeline described above, under
`<staticContentPath>/webjars/**` (by default `/static/webjars/**`). Resolution is **version-less**: you reference a
resource by its logical path and Struts resolves the version present on the classpath. For example, a request for:
```
/static/webjars/bootstrap/css/bootstrap.min.css
```
is served from `META-INF/resources/webjars/bootstrap/5.3.8/css/bootstrap.min.css` (whichever version is on the
classpath). To emit these URLs from a template without hardcoding the version, use the
[webjar tag](../tag-developers/webjar-tag):
```jsp
<link rel="stylesheet" href="<s:webjar path="bootstrap/css/bootstrap.min.css"/>"/>
```
Struts resolves versions using [webjars-locator-lite](https://github.com/webjars/webjars-locator-lite), which is bundled
with `struts2-core`.
### Configuration
| Constant | Default | Description |
|----------------------------|---------|---------------------------------------------------------------------------------------------------|
| `struts.webjars.enabled` | `true` | Master switch for resolving and serving WebJar assets under `<staticContentPath>/webjars/**`. |
| `struts.webjars.allowlist` | (empty) | Optional comma-separated allowlist of WebJar names. When empty, all WebJars on the classpath are allowed. |
To restrict serving to specific WebJars:
```xml
<constant name="struts.webjars.allowlist" value="bootstrap,jquery"/>
```
To disable the feature entirely:
```xml
<constant name="struts.webjars.enabled" value="false"/>
```
### Security
Resolution is hard-constrained to the `META-INF/resources/webjars/` root: path traversal attempts (`..`, `.`,
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
**fail closed** - a `404` when serving and empty output when building URLs.
### Customizing resolution
URL resolution is provided by the `org.apache.struts2.webjars.WebJarUrlProvider` container bean (default implementation
`DefaultWebJarUrlProvider`), which exposes `resolveResourcePath(String)` and `resolveUrl(String, HttpServletRequest)`.
Plugins and applications can replace it by declaring their own bean:
```xml
<bean type="org.apache.struts2.webjars.WebJarUrlProvider" class="com.example.MyWebJarUrlProvider" name="myProvider"/>
<constant name="struts.webjars.urlProvider" value="myProvider"/>
```
## Preventing Struts from handling a request
If there is a request that Struts is handling as an action, and you wish to make Struts ignore it,
you can do so by specifying a comma separated list of regular expressions like:
```xml
<constant name="struts.action.excludePattern" value="/some/content/.*,/other/content/.*"/>
```
These regular expression will be evaluated against the request's URI (`HttpServletRequest.getRequestURI()`), and if any
of them matches, then Struts will not handle the request.
To evaluate each pattern the `Pattern` class from JDK will be used, you can find more about what kind of pattern you can
use in the [Pattern class JavaDoc](http://docs.oracle.com/javase/1.5.0/docs/api/java/util/regex/Pattern).
Since Struts 6.1.0 you can use a custom separator. By default, the provided patterns are split using comma `,`,
but it can happen that you want to use comma in your patterns as well, e.g.: `/static/[a-z]{1,10}.json`. In such case
you can define a custom separator to be used to split the patterns, use `struts.action.excludePattern.separator`
constant:
```xml
<constant name="struts.action.excludePattern.separator" value="//"/>
<constant name="struts.action.excludePattern" value="/some/[a-zA-Z]{1,10}.json///other/content/.*"/>
```